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)
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include "wine/port.h"
34 #include <sys/types.h>
40 #ifdef HAVE_SYS_PARAM_H
41 # include <sys/param.h>
43 #ifdef STATFS_DEFINED_BY_SYS_VFS
46 # ifdef STATFS_DEFINED_BY_SYS_MOUNT
47 # include <sys/mount.h>
49 # ifdef STATFS_DEFINED_BY_SYS_STATFS
50 # include <sys/statfs.h>
57 #include "wine/winbase16.h" /* for GetCurrentTask */
64 #include "wine/debug.h"
65 #include "wine/server.h"
70 WINE_DEFAULT_DEBUG_CHANNEL(dosfs
);
71 WINE_DECLARE_DEBUG_CHANNEL(file
);
75 char *root
; /* root dir in Unix format without trailing / */
76 char *dos_cwd
; /* cwd in DOS format without leading or trailing \ */
77 char *unix_cwd
; /* cwd in Unix format without leading or trailing / */
78 char *device
; /* raw device path */
79 char label_conf
[12]; /* drive label as cfg'd in wine config */
80 char label_read
[12]; /* drive label as read from device */
81 DWORD serial_conf
; /* drive serial number as cfg'd in wine config */
82 UINT type
; /* drive type */
83 UINT flags
; /* drive flags */
84 dev_t dev
; /* unix device number */
85 ino_t ino
; /* unix inode number */
89 static const char * const DRIVE_Types
[] =
91 "", /* DRIVE_UNKNOWN */
92 "", /* DRIVE_NO_ROOT_DIR */
93 "floppy", /* DRIVE_REMOVABLE */
94 "hd", /* DRIVE_FIXED */
95 "network", /* DRIVE_REMOTE */
96 "cdrom", /* DRIVE_CDROM */
97 "ramdisk" /* DRIVE_RAMDISK */
101 /* Known filesystem types */
109 static const FS_DESCR DRIVE_Filesystems
[] =
111 { "unix", DRIVE_CASE_SENSITIVE
| DRIVE_CASE_PRESERVING
},
112 { "msdos", DRIVE_SHORT_NAMES
},
113 { "dos", DRIVE_SHORT_NAMES
},
114 { "fat", DRIVE_SHORT_NAMES
},
115 { "vfat", DRIVE_CASE_PRESERVING
},
116 { "win95", DRIVE_CASE_PRESERVING
},
121 static DOSDRIVE DOSDrives
[MAX_DOS_DRIVES
];
122 static int DRIVE_CurDrive
= -1;
124 static HTASK16 DRIVE_LastTask
= 0;
126 /* strdup on the process heap */
127 inline static char *heap_strdup( const char *str
)
129 INT len
= strlen(str
) + 1;
130 LPSTR p
= HeapAlloc( GetProcessHeap(), 0, len
);
131 if (p
) memcpy( p
, str
, len
);
135 extern void CDROM_InitRegistry(int dev
);
137 /***********************************************************************
140 static UINT
DRIVE_GetDriveType( const char *name
)
145 PROFILE_GetWineIniString( name
, "Type", "hd", buffer
, sizeof(buffer
) );
146 for (i
= 0; i
< sizeof(DRIVE_Types
)/sizeof(DRIVE_Types
[0]); i
++)
148 if (!strcasecmp( buffer
, DRIVE_Types
[i
] )) return i
;
150 MESSAGE("%s: unknown drive type '%s', defaulting to 'hd'.\n",
156 /***********************************************************************
159 static UINT
DRIVE_GetFSFlags( const char *name
, const char *value
)
161 const FS_DESCR
*descr
;
163 for (descr
= DRIVE_Filesystems
; descr
->name
; descr
++)
164 if (!strcasecmp( value
, descr
->name
)) return descr
->flags
;
165 MESSAGE("%s: unknown filesystem type '%s', defaulting to 'win95'.\n",
167 return DRIVE_CASE_PRESERVING
;
171 /***********************************************************************
176 int i
, len
, count
= 0;
177 char name
[] = "Drive A";
178 char drive_env
[] = "=A:";
179 char path
[MAX_PATHNAME_LEN
];
181 struct stat drive_stat_buffer
;
185 for (i
= 0, drive
= DOSDrives
; i
< MAX_DOS_DRIVES
; i
++, name
[6]++, drive
++)
187 PROFILE_GetWineIniString( name
, "Path", "", path
, sizeof(path
)-1 );
190 p
= path
+ strlen(path
) - 1;
191 while ((p
> path
) && (*p
== '/')) *p
-- = '\0';
195 drive
->root
= heap_strdup( path
);
199 /* relative paths are relative to config dir */
200 const char *config
= get_config_dir();
201 drive
->root
= HeapAlloc( GetProcessHeap(), 0, strlen(config
) + strlen(path
) + 2 );
202 sprintf( drive
->root
, "%s/%s", config
, path
);
205 if (stat( drive
->root
, &drive_stat_buffer
))
207 MESSAGE("Could not stat %s (%s), ignoring drive %c:\n",
208 drive
->root
, strerror(errno
), 'A' + i
);
209 HeapFree( GetProcessHeap(), 0, drive
->root
);
213 if (!S_ISDIR(drive_stat_buffer
.st_mode
))
215 MESSAGE("%s is not a directory, ignoring drive %c:\n",
216 drive
->root
, 'A' + i
);
217 HeapFree( GetProcessHeap(), 0, drive
->root
);
222 drive
->dos_cwd
= heap_strdup( "" );
223 drive
->unix_cwd
= heap_strdup( "" );
224 drive
->type
= DRIVE_GetDriveType( name
);
225 drive
->device
= NULL
;
227 drive
->dev
= drive_stat_buffer
.st_dev
;
228 drive
->ino
= drive_stat_buffer
.st_ino
;
230 /* Get the drive label */
231 PROFILE_GetWineIniString( name
, "Label", "", drive
->label_conf
, 12 );
232 if ((len
= strlen(drive
->label_conf
)) < 11)
234 /* Pad label with spaces */
235 memset( drive
->label_conf
+ len
, ' ', 11 - len
);
236 drive
->label_conf
[11] = '\0';
239 /* Get the serial number */
240 PROFILE_GetWineIniString( name
, "Serial", "12345678",
241 buffer
, sizeof(buffer
) );
242 drive
->serial_conf
= strtoul( buffer
, NULL
, 16 );
244 /* Get the filesystem type */
245 PROFILE_GetWineIniString( name
, "Filesystem", "win95",
246 buffer
, sizeof(buffer
) );
247 drive
->flags
= DRIVE_GetFSFlags( name
, buffer
);
250 PROFILE_GetWineIniString( name
, "Device", "",
251 buffer
, sizeof(buffer
) );
255 drive
->device
= heap_strdup( buffer
);
256 if (PROFILE_GetWineIniBool( name
, "ReadVolInfo", 1))
257 drive
->flags
|= DRIVE_READ_VOL_INFO
;
258 if (drive
->type
== DRIVE_CDROM
)
260 if ((cd_fd
= open(buffer
,O_RDONLY
|O_NONBLOCK
)) != -1) {
261 CDROM_InitRegistry(cd_fd
);
267 /* Get the FailReadOnly flag */
268 if (PROFILE_GetWineIniBool( name
, "FailReadOnly", 0 ))
269 drive
->flags
|= DRIVE_FAIL_READ_ONLY
;
271 /* Make the first hard disk the current drive */
272 if ((DRIVE_CurDrive
== -1) && (drive
->type
== DRIVE_FIXED
))
276 TRACE("%s: path=%s type=%s label='%s' serial=%08lx "
277 "flags=%08x dev=%x ino=%x\n",
278 name
, drive
->root
, DRIVE_Types
[drive
->type
],
279 drive
->label_conf
, drive
->serial_conf
, drive
->flags
,
280 (int)drive
->dev
, (int)drive
->ino
);
282 else WARN("%s: not defined\n", name
);
287 MESSAGE("Warning: no valid DOS drive found, check your configuration file.\n" );
288 /* Create a C drive pointing to Unix root dir */
289 DOSDrives
[2].root
= heap_strdup( "/" );
290 DOSDrives
[2].dos_cwd
= heap_strdup( "" );
291 DOSDrives
[2].unix_cwd
= heap_strdup( "" );
292 strcpy( DOSDrives
[2].label_conf
, "Drive C " );
293 DOSDrives
[2].serial_conf
= 12345678;
294 DOSDrives
[2].type
= DRIVE_FIXED
;
295 DOSDrives
[2].device
= NULL
;
296 DOSDrives
[2].flags
= 0;
300 /* Make sure the current drive is valid */
301 if (DRIVE_CurDrive
== -1)
303 for (i
= 0, drive
= DOSDrives
; i
< MAX_DOS_DRIVES
; i
++, drive
++)
305 if (drive
->root
&& !(drive
->flags
& DRIVE_DISABLED
))
313 /* get current working directory info for all drives */
314 for (i
= 0; i
< MAX_DOS_DRIVES
; i
++, drive_env
[1]++)
316 if (!GetEnvironmentVariableA(drive_env
, path
, sizeof(path
))) continue;
318 if (toupper(path
[0]) != drive_env
[1] || path
[1] != ':') continue;
319 DRIVE_Chdir( i
, path
+ 2 );
325 /***********************************************************************
328 int DRIVE_IsValid( int drive
)
330 if ((drive
< 0) || (drive
>= MAX_DOS_DRIVES
)) return 0;
331 return (DOSDrives
[drive
].root
&&
332 !(DOSDrives
[drive
].flags
& DRIVE_DISABLED
));
336 /***********************************************************************
337 * DRIVE_GetCurrentDrive
339 int DRIVE_GetCurrentDrive(void)
341 TDB
*pTask
= TASK_GetCurrent();
342 if (pTask
&& (pTask
->curdrive
& 0x80)) return pTask
->curdrive
& ~0x80;
343 return DRIVE_CurDrive
;
347 /***********************************************************************
348 * DRIVE_SetCurrentDrive
350 int DRIVE_SetCurrentDrive( int drive
)
352 TDB
*pTask
= TASK_GetCurrent();
353 if (!DRIVE_IsValid( drive
))
355 SetLastError( ERROR_INVALID_DRIVE
);
358 TRACE("%c:\n", 'A' + drive
);
359 DRIVE_CurDrive
= drive
;
360 if (pTask
) pTask
->curdrive
= drive
| 0x80;
361 chdir(DRIVE_GetUnixCwd(drive
));
366 /***********************************************************************
367 * DRIVE_FindDriveRoot
369 * Find a drive for which the root matches the beginning of the given path.
370 * This can be used to translate a Unix path into a drive + DOS path.
371 * Return value is the drive, or -1 on error. On success, path is modified
372 * to point to the beginning of the DOS path.
374 int DRIVE_FindDriveRoot( const char **path
)
376 /* Starting with the full path, check if the device and inode match any of
377 * the wine 'drives'. If not then remove the last path component and try
378 * again. If the last component was a '..' then skip a normal component
379 * since it's a directory that's ascended back out of.
381 int drive
, level
, len
;
382 char buffer
[MAX_PATHNAME_LEN
];
386 strcpy( buffer
, *path
);
387 while ((p
= strchr( buffer
, '\\' )) != NULL
)
389 len
= strlen(buffer
);
394 if (stat( buffer
, &st
) == 0 && S_ISDIR( st
.st_mode
))
396 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
398 if (!DOSDrives
[drive
].root
||
399 (DOSDrives
[drive
].flags
& DRIVE_DISABLED
))
402 if ((DOSDrives
[drive
].dev
== st
.st_dev
) &&
403 (DOSDrives
[drive
].ino
== st
.st_ino
))
405 TRACE( "%s -> drive %c:, root='%s', name='%s'\n",
406 *path
, 'A' + drive
, buffer
, *path
+ len
);
414 while (len
> 0 && level
< 1)
416 /* strip off a trailing slash */
417 while (len
> 0 && buffer
[len
- 1] == '/')
419 /* find start of the last path component */
420 while (len
> 0 && buffer
[len
- 1] != '/')
422 /* does removing it take us up a level? */
423 if (strcmp( buffer
+ len
, "." ) != 0)
424 level
+= strcmp( buffer
+ len
, ".." ) ? 1 : -1;
433 /***********************************************************************
436 const char * DRIVE_GetRoot( int drive
)
438 if (!DRIVE_IsValid( drive
)) return NULL
;
439 return DOSDrives
[drive
].root
;
443 /***********************************************************************
446 const char * DRIVE_GetDosCwd( int drive
)
448 TDB
*pTask
= TASK_GetCurrent();
449 if (!DRIVE_IsValid( drive
)) return NULL
;
451 /* Check if we need to change the directory to the new task. */
452 if (pTask
&& (pTask
->curdrive
& 0x80) && /* The task drive is valid */
453 ((pTask
->curdrive
& ~0x80) == drive
) && /* and it's the one we want */
454 (DRIVE_LastTask
!= GetCurrentTask())) /* and the task changed */
456 /* Perform the task-switch */
457 if (!DRIVE_Chdir( drive
, pTask
->curdir
)) DRIVE_Chdir( drive
, "\\" );
458 DRIVE_LastTask
= GetCurrentTask();
460 return DOSDrives
[drive
].dos_cwd
;
464 /***********************************************************************
467 const char * DRIVE_GetUnixCwd( int drive
)
469 TDB
*pTask
= TASK_GetCurrent();
470 if (!DRIVE_IsValid( drive
)) return NULL
;
472 /* Check if we need to change the directory to the new task. */
473 if (pTask
&& (pTask
->curdrive
& 0x80) && /* The task drive is valid */
474 ((pTask
->curdrive
& ~0x80) == drive
) && /* and it's the one we want */
475 (DRIVE_LastTask
!= GetCurrentTask())) /* and the task changed */
477 /* Perform the task-switch */
478 if (!DRIVE_Chdir( drive
, pTask
->curdir
)) DRIVE_Chdir( drive
, "\\" );
479 DRIVE_LastTask
= GetCurrentTask();
481 return DOSDrives
[drive
].unix_cwd
;
485 /***********************************************************************
488 const char * DRIVE_GetDevice( int drive
)
490 return (DRIVE_IsValid( drive
)) ? DOSDrives
[drive
].device
: NULL
;
493 /******************************************************************
494 * static WORD CDROM_Data_FindBestVoldesc
498 static WORD
CDROM_Data_FindBestVoldesc(int fd
)
500 BYTE cur_vd_type
, max_vd_type
= 0;
501 unsigned int offs
, best_offs
= 0, extra_offs
= 0;
504 for (offs
= 0x8000; offs
<= 0x9800; offs
+= 0x800)
506 /* if 'CDROM' occurs at position 8, this is a pre-iso9660 cd, and
507 * the volume label is displaced forward by 8
509 lseek(fd
, offs
+ 11, SEEK_SET
); /* check for non-ISO9660 signature */
511 if ((sig
[0] == 'R') && (sig
[1] == 'O') && (sig
[2]=='M'))
515 lseek(fd
, offs
+ extra_offs
, SEEK_SET
);
516 read(fd
, &cur_vd_type
, 1);
517 if (cur_vd_type
== 0xff) /* voldesc set terminator */
519 if (cur_vd_type
> max_vd_type
)
521 max_vd_type
= cur_vd_type
;
522 best_offs
= offs
+ extra_offs
;
528 /***********************************************************************
529 * DRIVE_ReadSuperblock
532 * DRIVE_SetLabel and DRIVE_SetSerialNumber use this in order
533 * to check, that they are writing on a FAT filesystem !
535 int DRIVE_ReadSuperblock (int drive
, char * buff
)
537 #define DRIVE_SUPER 96
542 if (memset(buff
,0,DRIVE_SUPER
)!=buff
) return -1;
543 if ((fd
=open(DOSDrives
[drive
].device
,O_RDONLY
)) == -1)
546 if (!DOSDrives
[drive
].device
)
547 ERR("No device configured for drive %c: !\n", 'A'+drive
);
549 ERR("Couldn't open device '%s' for drive %c: ! (%s)\n", DOSDrives
[drive
].device
, 'A'+drive
,
550 (stat(DOSDrives
[drive
].device
, &st
)) ?
551 "not available or symlink not valid ?" : "no permission");
552 ERR("Can't read drive volume info ! Either pre-set it or make sure the device to read it from is accessible !\n");
553 PROFILE_UsageWineIni();
557 switch(DOSDrives
[drive
].type
)
559 case DRIVE_REMOVABLE
:
564 offs
= CDROM_Data_FindBestVoldesc(fd
);
571 if ((offs
) && (lseek(fd
,offs
,SEEK_SET
)!=offs
))
576 if (read(fd
,buff
,DRIVE_SUPER
)!=DRIVE_SUPER
)
582 switch(DOSDrives
[drive
].type
)
584 case DRIVE_REMOVABLE
:
586 if ((buff
[0x26]!=0x29) || /* Check for FAT present */
587 /* FIXME: do really all FAT have their name beginning with
588 "FAT" ? (At least FAT12, FAT16 and FAT32 have :) */
589 memcmp( buff
+0x36,"FAT",3))
591 ERR("The filesystem is not FAT !! (device=%s)\n",
592 DOSDrives
[drive
].device
);
598 if (strncmp(&buff
[1],"CD001",5)) /* Check for iso9660 present */
603 /* FIXME: do we need to check for "CDROM", too ? (high sierra) */
617 /***********************************************************************
618 * DRIVE_WriteSuperblockEntry
621 * We are writing as little as possible (ie. not the whole SuperBlock)
622 * not to interfere with kernel. The drive can be mounted !
624 int DRIVE_WriteSuperblockEntry (int drive
, off_t ofs
, size_t len
, char * buff
)
628 if ((fd
=open(DOSDrives
[drive
].device
,O_WRONLY
))==-1)
630 ERR("Cannot open the device %s (for writing)\n",
631 DOSDrives
[drive
].device
);
634 if (lseek(fd
,ofs
,SEEK_SET
)!=ofs
)
636 ERR("lseek failed on device %s !\n",
637 DOSDrives
[drive
].device
);
641 if (write(fd
,buff
,len
)!=len
)
644 ERR("Cannot write on %s !\n",
645 DOSDrives
[drive
].device
);
651 /******************************************************************
652 * static HANDLE CDROM_Open
656 static HANDLE
CDROM_Open(int drive
)
660 strcpy(root
, "\\\\.\\A:");
663 return CreateFileA(root
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, 0);
666 /**************************************************************************
667 * CDROM_Data_GetLabel [internal]
669 DWORD
CDROM_Data_GetLabel(int drive
, char *label
)
671 #define LABEL_LEN 32+1
672 int dev
= open(DOSDrives
[drive
].device
, O_RDONLY
|O_NONBLOCK
);
673 WORD offs
= CDROM_Data_FindBestVoldesc(dev
);
674 WCHAR label_read
[LABEL_LEN
]; /* Unicode possible, too */
675 DWORD unicode_id
= 0;
679 if ((lseek(dev
, offs
+0x58, SEEK_SET
) == offs
+0x58)
680 && (read(dev
, &unicode_id
, 3) == 3))
682 int ver
= (unicode_id
& 0xff0000) >> 16;
684 if ((lseek(dev
, offs
+0x28, SEEK_SET
) != offs
+0x28)
685 || (read(dev
, &label_read
, LABEL_LEN
) != LABEL_LEN
))
689 if ((LOWORD(unicode_id
) == 0x2f25) /* Unicode ID */
690 && ((ver
== 0x40) || (ver
== 0x43) || (ver
== 0x45)))
691 { /* yippee, unicode */
694 for (i
=0; i
<LABEL_LEN
;i
++)
695 { /* Motorola -> Intel Unicode conversion :-\ */
697 label_read
[i
] = (ch
<< 8) | (ch
>> 8);
699 WideCharToMultiByte( CP_ACP
, 0, label_read
, -1, label
, 12, NULL
, NULL
);
704 strncpy(label
, (LPSTR
)label_read
, 11);
712 ERR("error reading label !\n");
716 /**************************************************************************
717 * CDROM_GetLabel [internal]
719 static DWORD
CDROM_GetLabel(int drive
, char *label
)
721 HANDLE h
= CDROM_Open(drive
);
726 if (!h
|| !DeviceIoControl(h
, IOCTL_CDROM_DISK_TYPE
, NULL
, 0, &cdd
, sizeof(cdd
), &br
, 0))
729 switch (cdd
.DiskData
& 0x03)
731 case CDROM_DISK_DATA_TRACK
:
732 if (!CDROM_Data_GetLabel(drive
, label
))
735 case CDROM_DISK_AUDIO_TRACK
:
736 strcpy(label
, "Audio CD ");
738 case CDROM_DISK_DATA_TRACK
|CDROM_DISK_AUDIO_TRACK
:
739 FIXME("Need to get the label of a mixed mode CD: not implemented yet !\n");
745 TRACE("CD: label is '%s'.\n", label
);
749 /***********************************************************************
752 const char * DRIVE_GetLabel( int drive
)
755 char buff
[DRIVE_SUPER
];
758 if (!DRIVE_IsValid( drive
)) return NULL
;
759 if (DOSDrives
[drive
].type
== DRIVE_CDROM
)
761 read
= CDROM_GetLabel(drive
, DOSDrives
[drive
].label_read
);
764 if (DOSDrives
[drive
].flags
& DRIVE_READ_VOL_INFO
)
766 if (DRIVE_ReadSuperblock(drive
,(char *) buff
))
767 ERR("Invalid or unreadable superblock on %s (%c:).\n",
768 DOSDrives
[drive
].device
, (char)(drive
+'A'));
770 if (DOSDrives
[drive
].type
== DRIVE_REMOVABLE
||
771 DOSDrives
[drive
].type
== DRIVE_FIXED
)
774 /* FIXME: ISO9660 uses a 32 bytes long label. Should we do also? */
775 if (offs
!= -1) memcpy(DOSDrives
[drive
].label_read
,buff
+offs
,11);
776 DOSDrives
[drive
].label_read
[11]='\0';
782 DOSDrives
[drive
].label_read
: DOSDrives
[drive
].label_conf
;
785 #define CDFRAMES_PERSEC 75
786 #define CDFRAMES_PERMIN (CDFRAMES_PERSEC * 60)
787 #define FRAME_OF_ADDR(a) ((a)[0] * CDFRAMES_PERMIN + (a)[1] * CDFRAMES_PERSEC + (a)[2])
788 #define FRAME_OF_TOC(toc, idx) FRAME_OF_ADDR((toc).TrackData[idx - (toc).FirstTrack].Address)
790 /**************************************************************************
791 * CDROM_Audio_GetSerial [internal]
793 static DWORD
CDROM_Audio_GetSerial(HANDLE h
)
795 unsigned long serial
= 0;
798 DWORD dwStart
, dwEnd
, br
;
801 if (!DeviceIoControl(h
, IOCTL_CDROM_READ_TOC
, NULL
, 0, &toc
, sizeof(toc
), &br
, 0))
805 * wMagic collects the wFrames from track 1
806 * dwStart, dwEnd collect the beginning and end of the disc respectively, in
808 * There it is collected for correcting the serial when there are less than
811 wMagic
= toc
.TrackData
[0].Address
[2];
812 dwStart
= FRAME_OF_TOC(toc
, toc
.FirstTrack
);
814 for (i
= 0; i
<= toc
.LastTrack
- toc
.FirstTrack
; i
++) {
815 serial
+= (toc
.TrackData
[i
].Address
[0] << 16) |
816 (toc
.TrackData
[i
].Address
[1] << 8) | toc
.TrackData
[i
].Address
[2];
818 dwEnd
= FRAME_OF_TOC(toc
, toc
.LastTrack
+ 1);
820 if (toc
.LastTrack
- toc
.FirstTrack
+ 1 < 3)
821 serial
+= wMagic
+ (dwEnd
- dwStart
);
826 /**************************************************************************
827 * CDROM_Data_GetSerial [internal]
829 static DWORD
CDROM_Data_GetSerial(int drive
)
831 int dev
= open(DOSDrives
[drive
].device
, O_RDONLY
|O_NONBLOCK
);
837 BYTE b0
= 0, b1
= 1, b2
= 2, b3
= 3;
840 if (dev
== -1) return 0;
841 offs
= CDROM_Data_FindBestVoldesc(dev
);
850 lseek(dev
, offs
, SEEK_SET
);
851 read(dev
, buf
, 2048);
853 * OK, another braindead one... argh. Just believe it.
854 * Me$$ysoft chose to reverse the serial number in NT4/W2K.
855 * It's true and nobody will ever be able to change it.
857 ovi
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOA
);
859 if ((ovi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) && (ovi
.dwMajorVersion
>= 4))
861 b0
= 3; b1
= 2; b2
= 1; b3
= 0;
863 for (i
= 0; i
< 2048; i
+= 4)
865 /* DON'T optimize this into DWORD !! (breaks overflow) */
866 serial
.p
[b0
] += buf
[i
+b0
];
867 serial
.p
[b1
] += buf
[i
+b1
];
868 serial
.p
[b2
] += buf
[i
+b2
];
869 serial
.p
[b3
] += buf
[i
+b3
];
876 /**************************************************************************
877 * CDROM_GetSerial [internal]
879 static DWORD
CDROM_GetSerial(int drive
)
882 HANDLE h
= CDROM_Open(drive
);
886 if (!h
|| ! !DeviceIoControl(h
, IOCTL_CDROM_DISK_TYPE
, NULL
, 0, &cdd
, sizeof(cdd
), &br
, 0))
889 switch (cdd
.DiskData
& 0x03)
891 case CDROM_DISK_DATA_TRACK
:
892 /* hopefully a data CD */
893 serial
= CDROM_Data_GetSerial(drive
);
895 case CDROM_DISK_AUDIO_TRACK
:
897 case CDROM_DISK_DATA_TRACK
|CDROM_DISK_AUDIO_TRACK
:
898 serial
= CDROM_Audio_GetSerial(h
);
905 TRACE("CD serial number is %04x-%04x.\n", HIWORD(serial
), LOWORD(serial
));
912 /***********************************************************************
913 * DRIVE_GetSerialNumber
915 DWORD
DRIVE_GetSerialNumber( int drive
)
918 char buff
[DRIVE_SUPER
];
920 if (!DRIVE_IsValid( drive
)) return 0;
922 if (DOSDrives
[drive
].flags
& DRIVE_READ_VOL_INFO
)
924 switch(DOSDrives
[drive
].type
)
926 case DRIVE_REMOVABLE
:
928 if (DRIVE_ReadSuperblock(drive
,(char *) buff
))
929 MESSAGE("Invalid or unreadable superblock on %s (%c:)."
930 " Maybe not FAT?\n" ,
931 DOSDrives
[drive
].device
, 'A'+drive
);
933 serial
= *((DWORD
*)(buff
+0x27));
936 serial
= CDROM_GetSerial(drive
);
939 FIXME("Serial number reading from file system on drive %c: not supported yet.\n", drive
+'A');
943 return (serial
) ? serial
: DOSDrives
[drive
].serial_conf
;
947 /***********************************************************************
948 * DRIVE_SetSerialNumber
950 int DRIVE_SetSerialNumber( int drive
, DWORD serial
)
952 char buff
[DRIVE_SUPER
];
954 if (!DRIVE_IsValid( drive
)) return 0;
956 if (DOSDrives
[drive
].flags
& DRIVE_READ_VOL_INFO
)
958 if ((DOSDrives
[drive
].type
!= DRIVE_REMOVABLE
) &&
959 (DOSDrives
[drive
].type
!= DRIVE_FIXED
)) return 0;
960 /* check, if the drive has a FAT filesystem */
961 if (DRIVE_ReadSuperblock(drive
, buff
)) return 0;
962 if (DRIVE_WriteSuperblockEntry(drive
, 0x27, 4, (char *) &serial
)) return 0;
966 if (DOSDrives
[drive
].type
== DRIVE_CDROM
) return 0;
967 DOSDrives
[drive
].serial_conf
= serial
;
972 /***********************************************************************
975 static UINT
DRIVE_GetType( int drive
)
977 if (!DRIVE_IsValid( drive
)) return DRIVE_UNKNOWN
;
978 return DOSDrives
[drive
].type
;
982 /***********************************************************************
985 UINT
DRIVE_GetFlags( int drive
)
987 if ((drive
< 0) || (drive
>= MAX_DOS_DRIVES
)) return 0;
988 return DOSDrives
[drive
].flags
;
992 /***********************************************************************
995 int DRIVE_Chdir( int drive
, const char *path
)
997 DOS_FULL_NAME full_name
;
998 char buffer
[MAX_PATHNAME_LEN
];
1000 BY_HANDLE_FILE_INFORMATION info
;
1001 TDB
*pTask
= TASK_GetCurrent();
1003 strcpy( buffer
, "A:" );
1005 TRACE("(%s,%s)\n", buffer
, path
);
1006 lstrcpynA( buffer
+ 2, path
, sizeof(buffer
) - 2 );
1008 if (!DOSFS_GetFullName( buffer
, TRUE
, &full_name
)) return 0;
1009 if (!FILE_Stat( full_name
.long_name
, &info
)) return 0;
1010 if (!(info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
))
1012 SetLastError( ERROR_FILE_NOT_FOUND
);
1015 unix_cwd
= full_name
.long_name
+ strlen( DOSDrives
[drive
].root
);
1016 while (*unix_cwd
== '/') unix_cwd
++;
1018 TRACE("(%c:): unix_cwd=%s dos_cwd=%s\n",
1019 'A' + drive
, unix_cwd
, full_name
.short_name
+ 3 );
1021 HeapFree( GetProcessHeap(), 0, DOSDrives
[drive
].dos_cwd
);
1022 HeapFree( GetProcessHeap(), 0, DOSDrives
[drive
].unix_cwd
);
1023 DOSDrives
[drive
].dos_cwd
= heap_strdup( full_name
.short_name
+ 3 );
1024 DOSDrives
[drive
].unix_cwd
= heap_strdup( unix_cwd
);
1026 if (pTask
&& (pTask
->curdrive
& 0x80) &&
1027 ((pTask
->curdrive
& ~0x80) == drive
))
1029 lstrcpynA( pTask
->curdir
, full_name
.short_name
+ 2,
1030 sizeof(pTask
->curdir
) );
1031 DRIVE_LastTask
= GetCurrentTask();
1032 chdir(unix_cwd
); /* Only change if on current drive */
1038 /***********************************************************************
1041 int DRIVE_Disable( int drive
)
1043 if ((drive
< 0) || (drive
>= MAX_DOS_DRIVES
) || !DOSDrives
[drive
].root
)
1045 SetLastError( ERROR_INVALID_DRIVE
);
1048 DOSDrives
[drive
].flags
|= DRIVE_DISABLED
;
1053 /***********************************************************************
1056 int DRIVE_Enable( int drive
)
1058 if ((drive
< 0) || (drive
>= MAX_DOS_DRIVES
) || !DOSDrives
[drive
].root
)
1060 SetLastError( ERROR_INVALID_DRIVE
);
1063 DOSDrives
[drive
].flags
&= ~DRIVE_DISABLED
;
1068 /***********************************************************************
1069 * DRIVE_SetLogicalMapping
1071 int DRIVE_SetLogicalMapping ( int existing_drive
, int new_drive
)
1073 /* If new_drive is already valid, do nothing and return 0
1074 otherwise, copy DOSDrives[existing_drive] to DOSDrives[new_drive] */
1076 DOSDRIVE
*old
, *new;
1078 old
= DOSDrives
+ existing_drive
;
1079 new = DOSDrives
+ new_drive
;
1081 if ((existing_drive
< 0) || (existing_drive
>= MAX_DOS_DRIVES
) ||
1083 (new_drive
< 0) || (new_drive
>= MAX_DOS_DRIVES
))
1085 SetLastError( ERROR_INVALID_DRIVE
);
1091 TRACE("Can't map drive %c: to already existing drive %c:\n",
1092 'A' + existing_drive
, 'A' + new_drive
);
1093 /* it is already mapped there, so return success */
1094 if (!strcmp(old
->root
,new->root
))
1099 new->root
= heap_strdup( old
->root
);
1100 new->dos_cwd
= heap_strdup( old
->dos_cwd
);
1101 new->unix_cwd
= heap_strdup( old
->unix_cwd
);
1102 new->device
= heap_strdup( old
->device
);
1103 memcpy ( new->label_conf
, old
->label_conf
, 12 );
1104 memcpy ( new->label_read
, old
->label_read
, 12 );
1105 new->serial_conf
= old
->serial_conf
;
1106 new->type
= old
->type
;
1107 new->flags
= old
->flags
;
1108 new->dev
= old
->dev
;
1109 new->ino
= old
->ino
;
1111 TRACE("Drive %c: is now equal to drive %c:\n",
1112 'A' + new_drive
, 'A' + existing_drive
);
1118 /***********************************************************************
1121 * Open the drive raw device and return a Unix fd (or -1 on error).
1123 int DRIVE_OpenDevice( int drive
, int flags
)
1125 if (!DRIVE_IsValid( drive
)) return -1;
1126 return open( DOSDrives
[drive
].device
, flags
);
1130 /***********************************************************************
1133 * Read raw sectors from a device
1135 int DRIVE_RawRead(BYTE drive
, DWORD begin
, DWORD nr_sect
, BYTE
*dataptr
, BOOL fake_success
)
1139 if ((fd
= DRIVE_OpenDevice( drive
, O_RDONLY
)) != -1)
1141 lseek( fd
, begin
* 512, SEEK_SET
);
1142 /* FIXME: check errors */
1143 read( fd
, dataptr
, nr_sect
* 512 );
1148 memset(dataptr
, 0, nr_sect
* 512);
1151 if (begin
== 0 && nr_sect
> 1) *(dataptr
+ 512) = 0xf8;
1152 if (begin
== 1) *dataptr
= 0xf8;
1161 /***********************************************************************
1164 * Write raw sectors to a device
1166 int DRIVE_RawWrite(BYTE drive
, DWORD begin
, DWORD nr_sect
, BYTE
*dataptr
, BOOL fake_success
)
1170 if ((fd
= DRIVE_OpenDevice( drive
, O_RDONLY
)) != -1)
1172 lseek( fd
, begin
* 512, SEEK_SET
);
1173 /* FIXME: check errors */
1174 write( fd
, dataptr
, nr_sect
* 512 );
1178 if (!(fake_success
))
1185 /***********************************************************************
1186 * DRIVE_GetFreeSpace
1188 static int DRIVE_GetFreeSpace( int drive
, PULARGE_INTEGER size
,
1189 PULARGE_INTEGER available
)
1193 if (!DRIVE_IsValid(drive
))
1195 SetLastError( ERROR_INVALID_DRIVE
);
1199 /* FIXME: add autoconf check for this */
1200 #if defined(__svr4__) || defined(_SCO_DS) || defined(__sun)
1201 if (statfs( DOSDrives
[drive
].root
, &info
, 0, 0) < 0)
1203 if (statfs( DOSDrives
[drive
].root
, &info
) < 0)
1207 WARN("cannot do statfs(%s)\n", DOSDrives
[drive
].root
);
1211 size
->QuadPart
= RtlEnlargedUnsignedMultiply( info
.f_bsize
, info
.f_blocks
);
1212 #ifdef STATFS_HAS_BAVAIL
1213 available
->QuadPart
= RtlEnlargedUnsignedMultiply( info
.f_bavail
, info
.f_bsize
);
1215 # ifdef STATFS_HAS_BFREE
1216 available
->QuadPart
= RtlEnlargedUnsignedMultiply( info
.f_bfree
, info
.f_bsize
);
1218 # error "statfs has no bfree/bavail member!"
1221 if (DOSDrives
[drive
].type
== DRIVE_CDROM
)
1222 { /* ALWAYS 0, even if no real CD-ROM mounted there !! */
1223 available
->QuadPart
= 0;
1228 /***********************************************************************
1229 * DRIVE_GetCurrentDirectory
1230 * Returns "X:\\path\\etc\\".
1232 * Despite the API description, return required length including the
1233 * terminating null when buffer too small. This is the real behaviour.
1236 static UINT
DRIVE_GetCurrentDirectory( UINT buflen
, LPSTR buf
)
1239 const char *s
= DRIVE_GetDosCwd( DRIVE_GetCurrentDrive() );
1242 ret
= strlen(s
) + 3; /* length of WHOLE current directory */
1243 if (ret
>= buflen
) return ret
+ 1;
1244 lstrcpynA( buf
, "A:\\", min( 4u, buflen
) );
1245 if (buflen
) buf
[0] += DRIVE_GetCurrentDrive();
1246 if (buflen
> 3) lstrcpynA( buf
+ 3, s
, buflen
- 3 );
1251 /***********************************************************************
1254 * Build the environment array containing the drives' current directories.
1255 * Resulting pointer must be freed with HeapFree.
1257 char *DRIVE_BuildEnv(void)
1260 const char *cwd
[MAX_DOS_DRIVES
];
1263 for (i
= 0; i
< MAX_DOS_DRIVES
; i
++)
1265 if ((cwd
[i
] = DRIVE_GetDosCwd(i
)) && cwd
[i
][0]) length
+= strlen(cwd
[i
]) + 8;
1267 if (!(env
= HeapAlloc( GetProcessHeap(), 0, length
+1 ))) return NULL
;
1268 for (i
= 0, p
= env
; i
< MAX_DOS_DRIVES
; i
++)
1270 if (cwd
[i
] && cwd
[i
][0])
1271 p
+= sprintf( p
, "=%c:=%c:\\%s", 'A'+i
, 'A'+i
, cwd
[i
] ) + 1;
1278 /***********************************************************************
1279 * GetDiskFreeSpace (KERNEL.422)
1281 BOOL16 WINAPI
GetDiskFreeSpace16( LPCSTR root
, LPDWORD cluster_sectors
,
1282 LPDWORD sector_bytes
, LPDWORD free_clusters
,
1283 LPDWORD total_clusters
)
1285 return GetDiskFreeSpaceA( root
, cluster_sectors
, sector_bytes
,
1286 free_clusters
, total_clusters
);
1290 /***********************************************************************
1291 * GetDiskFreeSpaceA (KERNEL32.@)
1293 * Fails if expression resulting from current drive's dir and "root"
1294 * is not a root dir of the target drive.
1296 * UNDOC: setting some LPDWORDs to NULL is perfectly possible
1297 * if the corresponding info is unneeded.
1299 * FIXME: needs to support UNC names from Win95 OSR2 on.
1301 * Behaviour under Win95a:
1302 * CurrDir root result
1303 * "E:\\TEST" "E:" FALSE
1307 * "E:\\TEST" "\\" TRUE
1308 * "E:\\TEST" ":\\" FALSE
1309 * "E:\\TEST" "E:\\" TRUE
1310 * "E:\\TEST" "" FALSE
1311 * "E:\\" "" FALSE (!)
1313 * "E:\\TEST" 0x0 TRUE (!)
1314 * "E:\\TEST" "C:" TRUE (when CurrDir of "C:" set to "\\")
1315 * "E:\\TEST" "C:" FALSE (when CurrDir of "C:" set to "\\TEST")
1317 BOOL WINAPI
GetDiskFreeSpaceA( LPCSTR root
, LPDWORD cluster_sectors
,
1318 LPDWORD sector_bytes
, LPDWORD free_clusters
,
1319 LPDWORD total_clusters
)
1321 int drive
, sec_size
;
1322 ULARGE_INTEGER size
,available
;
1326 if ((!root
) || (strcmp(root
,"\\") == 0))
1327 drive
= DRIVE_GetCurrentDrive();
1329 if ( (strlen(root
) >= 2) && (root
[1] == ':')) /* root contains drive tag */
1331 drive
= toupper(root
[0]) - 'A';
1333 if (path
[0] == '\0')
1334 path
= DRIVE_GetDosCwd(drive
);
1336 if (path
[0] == '\\')
1338 if (path
[0]) /* oops, we are in a subdir */
1340 SetLastError(ERROR_INVALID_NAME
);
1346 SetLastError(ERROR_INVALID_NAME
);
1350 if (!DRIVE_GetFreeSpace(drive
, &size
, &available
)) return FALSE
;
1352 /* Cap the size and available at 2GB as per specs. */
1353 if ((size
.s
.HighPart
) ||(size
.s
.LowPart
> 0x7fffffff))
1355 size
.s
.HighPart
= 0;
1356 size
.s
.LowPart
= 0x7fffffff;
1358 if ((available
.s
.HighPart
) ||(available
.s
.LowPart
> 0x7fffffff))
1360 available
.s
.HighPart
=0;
1361 available
.s
.LowPart
= 0x7fffffff;
1363 sec_size
= (DRIVE_GetType(drive
)==DRIVE_CDROM
) ? 2048 : 512;
1364 size
.s
.LowPart
/= sec_size
;
1365 available
.s
.LowPart
/= sec_size
;
1366 /* FIXME: probably have to adjust those variables too for CDFS */
1368 while (cluster_sec
* 65536 < size
.s
.LowPart
) cluster_sec
*= 2;
1370 if (cluster_sectors
)
1371 *cluster_sectors
= cluster_sec
;
1373 *sector_bytes
= sec_size
;
1375 *free_clusters
= available
.s
.LowPart
/ cluster_sec
;
1377 *total_clusters
= size
.s
.LowPart
/ cluster_sec
;
1382 /***********************************************************************
1383 * GetDiskFreeSpaceW (KERNEL32.@)
1385 BOOL WINAPI
GetDiskFreeSpaceW( LPCWSTR root
, LPDWORD cluster_sectors
,
1386 LPDWORD sector_bytes
, LPDWORD free_clusters
,
1387 LPDWORD total_clusters
)
1392 xroot
= HEAP_strdupWtoA( GetProcessHeap(), 0, root
);
1393 ret
= GetDiskFreeSpaceA( xroot
,cluster_sectors
, sector_bytes
,
1394 free_clusters
, total_clusters
);
1395 HeapFree( GetProcessHeap(), 0, xroot
);
1400 /***********************************************************************
1401 * GetDiskFreeSpaceExA (KERNEL32.@)
1403 * This function is used to acquire the size of the available and
1404 * total space on a logical volume.
1408 * Zero on failure, nonzero upon success. Use GetLastError to obtain
1409 * detailed error information.
1412 BOOL WINAPI
GetDiskFreeSpaceExA( LPCSTR root
,
1413 PULARGE_INTEGER avail
,
1414 PULARGE_INTEGER total
,
1415 PULARGE_INTEGER totalfree
)
1418 ULARGE_INTEGER size
,available
;
1420 if (!root
) drive
= DRIVE_GetCurrentDrive();
1422 { /* C: always works for GetDiskFreeSpaceEx */
1423 if ((root
[1]) && ((root
[1] != ':') || (root
[2] && root
[2] != '\\')))
1425 FIXME("there are valid root names which are not supported yet\n");
1426 /* ..like UNC names, for instance. */
1428 WARN("invalid root '%s'\n", root
);
1431 drive
= toupper(root
[0]) - 'A';
1434 if (!DRIVE_GetFreeSpace(drive
, &size
, &available
)) return FALSE
;
1438 total
->s
.HighPart
= size
.s
.HighPart
;
1439 total
->s
.LowPart
= size
.s
.LowPart
;
1444 totalfree
->s
.HighPart
= available
.s
.HighPart
;
1445 totalfree
->s
.LowPart
= available
.s
.LowPart
;
1450 if (FIXME_ON(dosfs
))
1452 /* On Windows2000, we need to check the disk quota
1453 allocated for the user owning the calling process. We
1454 don't want to be more obtrusive than necessary with the
1455 FIXME messages, so don't print the FIXME unless Wine is
1456 actually masquerading as Windows2000. */
1459 ovi
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOA
);
1460 if (GetVersionExA(&ovi
))
1462 if (ovi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
&& ovi
.dwMajorVersion
> 4)
1463 FIXME("no per-user quota support yet\n");
1467 /* Quick hack, should eventually be fixed to work 100% with
1468 Windows2000 (see comment above). */
1469 avail
->s
.HighPart
= available
.s
.HighPart
;
1470 avail
->s
.LowPart
= available
.s
.LowPart
;
1476 /***********************************************************************
1477 * GetDiskFreeSpaceExW (KERNEL32.@)
1479 BOOL WINAPI
GetDiskFreeSpaceExW( LPCWSTR root
, PULARGE_INTEGER avail
,
1480 PULARGE_INTEGER total
,
1481 PULARGE_INTEGER totalfree
)
1486 xroot
= HEAP_strdupWtoA( GetProcessHeap(), 0, root
);
1487 ret
= GetDiskFreeSpaceExA( xroot
, avail
, total
, totalfree
);
1488 HeapFree( GetProcessHeap(), 0, xroot
);
1492 /***********************************************************************
1493 * GetDriveType (KERNEL.136)
1494 * This function returns the type of a drive in Win16.
1495 * Note that it returns DRIVE_REMOTE for CD-ROMs, since MSCDEX uses the
1496 * remote drive API. The return value DRIVE_REMOTE for CD-ROMs has been
1497 * verified on Win 3.11 and Windows 95. Some programs rely on it, so don't
1498 * do any pseudo-clever changes.
1501 * drivetype DRIVE_xxx
1503 UINT16 WINAPI
GetDriveType16( UINT16 drive
) /* [in] number (NOT letter) of drive */
1505 UINT type
= DRIVE_GetType(drive
);
1506 TRACE("(%c:)\n", 'A' + drive
);
1507 if (type
== DRIVE_CDROM
) type
= DRIVE_REMOTE
;
1512 /***********************************************************************
1513 * GetDriveTypeA (KERNEL32.@)
1515 * Returns the type of the disk drive specified. If root is NULL the
1516 * root of the current directory is used.
1520 * Type of drive (from Win32 SDK):
1522 * DRIVE_UNKNOWN unable to find out anything about the drive
1523 * DRIVE_NO_ROOT_DIR nonexistent root dir
1524 * DRIVE_REMOVABLE the disk can be removed from the machine
1525 * DRIVE_FIXED the disk can not be removed from the machine
1526 * DRIVE_REMOTE network disk
1527 * DRIVE_CDROM CDROM drive
1528 * DRIVE_RAMDISK virtual disk in RAM
1530 UINT WINAPI
GetDriveTypeA(LPCSTR root
) /* [in] String describing drive */
1533 TRACE("(%s)\n", debugstr_a(root
));
1535 if (NULL
== root
) drive
= DRIVE_GetCurrentDrive();
1538 if ((root
[1]) && (root
[1] != ':'))
1540 WARN("invalid root %s\n", debugstr_a(root
));
1541 return DRIVE_NO_ROOT_DIR
;
1543 drive
= toupper(root
[0]) - 'A';
1545 return DRIVE_GetType(drive
);
1549 /***********************************************************************
1550 * GetDriveTypeW (KERNEL32.@)
1552 UINT WINAPI
GetDriveTypeW( LPCWSTR root
)
1554 LPSTR xpath
= HEAP_strdupWtoA( GetProcessHeap(), 0, root
);
1555 UINT ret
= GetDriveTypeA( xpath
);
1556 HeapFree( GetProcessHeap(), 0, xpath
);
1561 /***********************************************************************
1562 * GetCurrentDirectory (KERNEL.411)
1564 UINT16 WINAPI
GetCurrentDirectory16( UINT16 buflen
, LPSTR buf
)
1566 return (UINT16
)DRIVE_GetCurrentDirectory(buflen
, buf
);
1570 /***********************************************************************
1571 * GetCurrentDirectoryA (KERNEL32.@)
1573 UINT WINAPI
GetCurrentDirectoryA( UINT buflen
, LPSTR buf
)
1576 char longname
[MAX_PATHNAME_LEN
];
1577 char shortname
[MAX_PATHNAME_LEN
];
1578 ret
= DRIVE_GetCurrentDirectory(MAX_PATHNAME_LEN
, shortname
);
1579 if ( ret
> MAX_PATHNAME_LEN
) {
1580 ERR_(file
)("pathnamelength (%d) > MAX_PATHNAME_LEN!\n", ret
);
1583 GetLongPathNameA(shortname
, longname
, MAX_PATHNAME_LEN
);
1584 ret
= strlen( longname
) + 1;
1585 if (ret
> buflen
) return ret
;
1586 strcpy(buf
, longname
);
1590 /***********************************************************************
1591 * GetCurrentDirectoryW (KERNEL32.@)
1593 UINT WINAPI
GetCurrentDirectoryW( UINT buflen
, LPWSTR buf
)
1595 LPSTR xpath
= HeapAlloc( GetProcessHeap(), 0, buflen
+1 );
1596 UINT ret
= GetCurrentDirectoryA( buflen
, xpath
);
1597 if (ret
< buflen
) ret
= MultiByteToWideChar( CP_ACP
, 0, xpath
, -1, buf
, buflen
) - 1;
1598 HeapFree( GetProcessHeap(), 0, xpath
);
1603 /***********************************************************************
1604 * SetCurrentDirectory (KERNEL.412)
1606 BOOL16 WINAPI
SetCurrentDirectory16( LPCSTR dir
)
1608 return SetCurrentDirectoryA( dir
);
1612 /***********************************************************************
1613 * SetCurrentDirectoryA (KERNEL32.@)
1615 BOOL WINAPI
SetCurrentDirectoryA( LPCSTR dir
)
1617 int drive
, olddrive
= DRIVE_GetCurrentDrive();
1620 ERR_(file
)("(NULL)!\n");
1623 if (dir
[0] && (dir
[1]==':'))
1625 drive
= toupper( *dir
) - 'A';
1631 /* WARNING: we need to set the drive before the dir, as DRIVE_Chdir
1632 sets pTask->curdir only if pTask->curdrive is drive */
1633 if (!(DRIVE_SetCurrentDrive( drive
)))
1635 /* FIXME: what about empty strings? Add a \\ ? */
1636 if (!DRIVE_Chdir( drive
, dir
)) {
1637 DRIVE_SetCurrentDrive(olddrive
);
1644 /***********************************************************************
1645 * SetCurrentDirectoryW (KERNEL32.@)
1647 BOOL WINAPI
SetCurrentDirectoryW( LPCWSTR dirW
)
1649 LPSTR dir
= HEAP_strdupWtoA( GetProcessHeap(), 0, dirW
);
1650 BOOL res
= SetCurrentDirectoryA( dir
);
1651 HeapFree( GetProcessHeap(), 0, dir
);
1656 /***********************************************************************
1657 * GetLogicalDriveStringsA (KERNEL32.@)
1659 UINT WINAPI
GetLogicalDriveStringsA( UINT len
, LPSTR buffer
)
1663 for (drive
= count
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
1664 if (DRIVE_IsValid(drive
)) count
++;
1665 if ((count
* 4) + 1 <= len
)
1668 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
1669 if (DRIVE_IsValid(drive
))
1680 return (count
* 4) + 1; /* account for terminating null */
1681 /* The API tells about these different return values */
1685 /***********************************************************************
1686 * GetLogicalDriveStringsW (KERNEL32.@)
1688 UINT WINAPI
GetLogicalDriveStringsW( UINT len
, LPWSTR buffer
)
1692 for (drive
= count
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
1693 if (DRIVE_IsValid(drive
)) count
++;
1694 if (count
* 4 * sizeof(WCHAR
) <= len
)
1697 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
1698 if (DRIVE_IsValid(drive
))
1700 *p
++ = (WCHAR
)('a' + drive
);
1707 return count
* 4 * sizeof(WCHAR
);
1711 /***********************************************************************
1712 * GetLogicalDrives (KERNEL32.@)
1714 DWORD WINAPI
GetLogicalDrives(void)
1719 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
1721 if ( (DRIVE_IsValid(drive
)) ||
1722 (DOSDrives
[drive
].type
== DRIVE_CDROM
)) /* audio CD is also valid */
1723 ret
|= (1 << drive
);
1729 /***********************************************************************
1730 * GetVolumeInformationA (KERNEL32.@)
1732 BOOL WINAPI
GetVolumeInformationA( LPCSTR root
, LPSTR label
,
1733 DWORD label_len
, DWORD
*serial
,
1734 DWORD
*filename_len
, DWORD
*flags
,
1735 LPSTR fsname
, DWORD fsname_len
)
1740 /* FIXME, SetLastError()s missing */
1742 if (!root
) drive
= DRIVE_GetCurrentDrive();
1745 if ((root
[1]) && (root
[1] != ':'))
1747 WARN("invalid root '%s'\n",root
);
1750 drive
= toupper(root
[0]) - 'A';
1752 if (!DRIVE_IsValid( drive
)) return FALSE
;
1755 lstrcpynA( label
, DRIVE_GetLabel(drive
), label_len
);
1756 cp
= label
+ strlen(label
);
1757 while (cp
!= label
&& *(cp
-1) == ' ') cp
--;
1760 if (serial
) *serial
= DRIVE_GetSerialNumber(drive
);
1762 /* Set the filesystem information */
1763 /* Note: we only emulate a FAT fs at present */
1766 if (DOSDrives
[drive
].flags
& DRIVE_SHORT_NAMES
)
1769 *filename_len
= 255;
1774 if (DOSDrives
[drive
].flags
& DRIVE_CASE_SENSITIVE
)
1775 *flags
|=FS_CASE_SENSITIVE
;
1776 if (DOSDrives
[drive
].flags
& DRIVE_CASE_PRESERVING
)
1777 *flags
|=FS_CASE_IS_PRESERVED
;
1780 /* Diablo checks that return code ... */
1781 if (DOSDrives
[drive
].type
== DRIVE_CDROM
)
1782 lstrcpynA( fsname
, "CDFS", fsname_len
);
1784 lstrcpynA( fsname
, "FAT", fsname_len
);
1790 /***********************************************************************
1791 * GetVolumeInformationW (KERNEL32.@)
1793 BOOL WINAPI
GetVolumeInformationW( LPCWSTR root
, LPWSTR label
,
1794 DWORD label_len
, DWORD
*serial
,
1795 DWORD
*filename_len
, DWORD
*flags
,
1796 LPWSTR fsname
, DWORD fsname_len
)
1798 LPSTR xroot
= HEAP_strdupWtoA( GetProcessHeap(), 0, root
);
1799 LPSTR xvolname
= label
? HeapAlloc(GetProcessHeap(),0,label_len
) : NULL
;
1800 LPSTR xfsname
= fsname
? HeapAlloc(GetProcessHeap(),0,fsname_len
) : NULL
;
1801 BOOL ret
= GetVolumeInformationA( xroot
, xvolname
, label_len
, serial
,
1802 filename_len
, flags
, xfsname
,
1806 if (label
) MultiByteToWideChar( CP_ACP
, 0, xvolname
, -1, label
, label_len
);
1807 if (fsname
) MultiByteToWideChar( CP_ACP
, 0, xfsname
, -1, fsname
, fsname_len
);
1809 HeapFree( GetProcessHeap(), 0, xroot
);
1810 HeapFree( GetProcessHeap(), 0, xvolname
);
1811 HeapFree( GetProcessHeap(), 0, xfsname
);
1815 /***********************************************************************
1816 * SetVolumeLabelA (KERNEL32.@)
1818 BOOL WINAPI
SetVolumeLabelA( LPCSTR root
, LPCSTR volname
)
1822 /* FIXME, SetLastErrors missing */
1824 if (!root
) drive
= DRIVE_GetCurrentDrive();
1827 if ((root
[1]) && (root
[1] != ':'))
1829 WARN("invalid root '%s'\n",root
);
1832 drive
= toupper(root
[0]) - 'A';
1834 if (!DRIVE_IsValid( drive
)) return FALSE
;
1836 /* some copy protection stuff check this */
1837 if (DOSDrives
[drive
].type
== DRIVE_CDROM
) return FALSE
;
1839 FIXME("(%s,%s),stub!\n", root
, volname
);
1843 /***********************************************************************
1844 * SetVolumeLabelW (KERNEL32.@)
1846 BOOL WINAPI
SetVolumeLabelW(LPCWSTR rootpath
,LPCWSTR volname
)
1851 xroot
= HEAP_strdupWtoA( GetProcessHeap(), 0, rootpath
);
1852 xvol
= HEAP_strdupWtoA( GetProcessHeap(), 0, volname
);
1853 ret
= SetVolumeLabelA( xroot
, xvol
);
1854 HeapFree( GetProcessHeap(), 0, xroot
);
1855 HeapFree( GetProcessHeap(), 0, xvol
);