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 */
65 #include "wine/debug.h"
66 #include "wine/server.h"
71 WINE_DEFAULT_DEBUG_CHANNEL(dosfs
);
72 WINE_DECLARE_DEBUG_CHANNEL(file
);
76 char *root
; /* root dir in Unix format without trailing / */
77 char *dos_cwd
; /* cwd in DOS format without leading or trailing \ */
78 char *unix_cwd
; /* cwd in Unix format without leading or trailing / */
79 char *device
; /* raw device path */
80 char label_conf
[12]; /* drive label as cfg'd in wine config */
81 char label_read
[12]; /* drive label as read from device */
82 DWORD serial_conf
; /* drive serial number as cfg'd in wine config */
83 UINT type
; /* drive type */
84 UINT flags
; /* drive flags */
85 dev_t dev
; /* unix device number */
86 ino_t ino
; /* unix inode number */
90 static const char * const DRIVE_Types
[] =
92 "", /* DRIVE_UNKNOWN */
93 "", /* DRIVE_NO_ROOT_DIR */
94 "floppy", /* DRIVE_REMOVABLE */
95 "hd", /* DRIVE_FIXED */
96 "network", /* DRIVE_REMOTE */
97 "cdrom", /* DRIVE_CDROM */
98 "ramdisk" /* DRIVE_RAMDISK */
102 /* Known filesystem types */
110 static const FS_DESCR DRIVE_Filesystems
[] =
112 { "unix", DRIVE_CASE_SENSITIVE
| DRIVE_CASE_PRESERVING
},
113 { "msdos", DRIVE_SHORT_NAMES
},
114 { "dos", DRIVE_SHORT_NAMES
},
115 { "fat", DRIVE_SHORT_NAMES
},
116 { "vfat", DRIVE_CASE_PRESERVING
},
117 { "win95", DRIVE_CASE_PRESERVING
},
122 static DOSDRIVE DOSDrives
[MAX_DOS_DRIVES
];
123 static int DRIVE_CurDrive
= -1;
125 static HTASK16 DRIVE_LastTask
= 0;
127 /* strdup on the process heap */
128 inline static char *heap_strdup( const char *str
)
130 INT len
= strlen(str
) + 1;
131 LPSTR p
= HeapAlloc( GetProcessHeap(), 0, len
);
132 if (p
) memcpy( p
, str
, len
);
136 extern void CDROM_InitRegistry(int dev
);
138 /***********************************************************************
141 static UINT
DRIVE_GetDriveType( const char *name
)
146 PROFILE_GetWineIniString( name
, "Type", "hd", buffer
, sizeof(buffer
) );
147 for (i
= 0; i
< sizeof(DRIVE_Types
)/sizeof(DRIVE_Types
[0]); i
++)
149 if (!strcasecmp( buffer
, DRIVE_Types
[i
] )) return i
;
151 MESSAGE("%s: unknown drive type '%s', defaulting to 'hd'.\n",
157 /***********************************************************************
160 static UINT
DRIVE_GetFSFlags( const char *name
, const char *value
)
162 const FS_DESCR
*descr
;
164 for (descr
= DRIVE_Filesystems
; descr
->name
; descr
++)
165 if (!strcasecmp( value
, descr
->name
)) return descr
->flags
;
166 MESSAGE("%s: unknown filesystem type '%s', defaulting to 'win95'.\n",
168 return DRIVE_CASE_PRESERVING
;
172 /***********************************************************************
177 int i
, len
, count
= 0;
178 char name
[] = "Drive A";
179 char drive_env
[] = "=A:";
180 char path
[MAX_PATHNAME_LEN
];
182 struct stat drive_stat_buffer
;
186 for (i
= 0, drive
= DOSDrives
; i
< MAX_DOS_DRIVES
; i
++, name
[6]++, drive
++)
188 PROFILE_GetWineIniString( name
, "Path", "", path
, sizeof(path
)-1 );
191 p
= path
+ strlen(path
) - 1;
192 while ((p
> path
) && (*p
== '/')) *p
-- = '\0';
196 drive
->root
= heap_strdup( path
);
200 /* relative paths are relative to config dir */
201 const char *config
= get_config_dir();
202 drive
->root
= HeapAlloc( GetProcessHeap(), 0, strlen(config
) + strlen(path
) + 2 );
203 sprintf( drive
->root
, "%s/%s", config
, path
);
206 if (stat( drive
->root
, &drive_stat_buffer
))
208 MESSAGE("Could not stat %s (%s), ignoring drive %c:\n",
209 drive
->root
, strerror(errno
), 'A' + i
);
210 HeapFree( GetProcessHeap(), 0, drive
->root
);
214 if (!S_ISDIR(drive_stat_buffer
.st_mode
))
216 MESSAGE("%s is not a directory, ignoring drive %c:\n",
217 drive
->root
, 'A' + i
);
218 HeapFree( GetProcessHeap(), 0, drive
->root
);
223 drive
->dos_cwd
= heap_strdup( "" );
224 drive
->unix_cwd
= heap_strdup( "" );
225 drive
->type
= DRIVE_GetDriveType( name
);
226 drive
->device
= NULL
;
228 drive
->dev
= drive_stat_buffer
.st_dev
;
229 drive
->ino
= drive_stat_buffer
.st_ino
;
231 /* Get the drive label */
232 PROFILE_GetWineIniString( name
, "Label", "", drive
->label_conf
, 12 );
233 if ((len
= strlen(drive
->label_conf
)) < 11)
235 /* Pad label with spaces */
236 memset( drive
->label_conf
+ len
, ' ', 11 - len
);
237 drive
->label_conf
[11] = '\0';
240 /* Get the serial number */
241 PROFILE_GetWineIniString( name
, "Serial", "12345678",
242 buffer
, sizeof(buffer
) );
243 drive
->serial_conf
= strtoul( buffer
, NULL
, 16 );
245 /* Get the filesystem type */
246 PROFILE_GetWineIniString( name
, "Filesystem", "win95",
247 buffer
, sizeof(buffer
) );
248 drive
->flags
= DRIVE_GetFSFlags( name
, buffer
);
251 PROFILE_GetWineIniString( name
, "Device", "",
252 buffer
, sizeof(buffer
) );
256 drive
->device
= heap_strdup( buffer
);
257 if (PROFILE_GetWineIniBool( name
, "ReadVolInfo", 1))
258 drive
->flags
|= DRIVE_READ_VOL_INFO
;
259 if (drive
->type
== DRIVE_CDROM
)
261 if ((cd_fd
= open(buffer
,O_RDONLY
|O_NONBLOCK
)) != -1) {
262 CDROM_InitRegistry(cd_fd
);
268 /* Get the FailReadOnly flag */
269 if (PROFILE_GetWineIniBool( name
, "FailReadOnly", 0 ))
270 drive
->flags
|= DRIVE_FAIL_READ_ONLY
;
272 /* Make the first hard disk the current drive */
273 if ((DRIVE_CurDrive
== -1) && (drive
->type
== DRIVE_FIXED
))
277 TRACE("%s: path=%s type=%s label='%s' serial=%08lx "
278 "flags=%08x dev=%x ino=%x\n",
279 name
, drive
->root
, DRIVE_Types
[drive
->type
],
280 drive
->label_conf
, drive
->serial_conf
, drive
->flags
,
281 (int)drive
->dev
, (int)drive
->ino
);
283 else WARN("%s: not defined\n", name
);
288 MESSAGE("Warning: no valid DOS drive found, check your configuration file.\n" );
289 /* Create a C drive pointing to Unix root dir */
290 DOSDrives
[2].root
= heap_strdup( "/" );
291 DOSDrives
[2].dos_cwd
= heap_strdup( "" );
292 DOSDrives
[2].unix_cwd
= heap_strdup( "" );
293 strcpy( DOSDrives
[2].label_conf
, "Drive C " );
294 DOSDrives
[2].serial_conf
= 12345678;
295 DOSDrives
[2].type
= DRIVE_FIXED
;
296 DOSDrives
[2].device
= NULL
;
297 DOSDrives
[2].flags
= 0;
301 /* Make sure the current drive is valid */
302 if (DRIVE_CurDrive
== -1)
304 for (i
= 0, drive
= DOSDrives
; i
< MAX_DOS_DRIVES
; i
++, drive
++)
306 if (drive
->root
&& !(drive
->flags
& DRIVE_DISABLED
))
314 /* get current working directory info for all drives */
315 for (i
= 0; i
< MAX_DOS_DRIVES
; i
++, drive_env
[1]++)
317 if (!GetEnvironmentVariableA(drive_env
, path
, sizeof(path
))) continue;
319 if (toupper(path
[0]) != drive_env
[1] || path
[1] != ':') continue;
320 DRIVE_Chdir( i
, path
+ 2 );
326 /***********************************************************************
329 int DRIVE_IsValid( int drive
)
331 if ((drive
< 0) || (drive
>= MAX_DOS_DRIVES
)) return 0;
332 return (DOSDrives
[drive
].root
&&
333 !(DOSDrives
[drive
].flags
& DRIVE_DISABLED
));
337 /***********************************************************************
338 * DRIVE_GetCurrentDrive
340 int DRIVE_GetCurrentDrive(void)
342 TDB
*pTask
= TASK_GetCurrent();
343 if (pTask
&& (pTask
->curdrive
& 0x80)) return pTask
->curdrive
& ~0x80;
344 return DRIVE_CurDrive
;
348 /***********************************************************************
349 * DRIVE_SetCurrentDrive
351 int DRIVE_SetCurrentDrive( int drive
)
353 TDB
*pTask
= TASK_GetCurrent();
354 if (!DRIVE_IsValid( drive
))
356 SetLastError( ERROR_INVALID_DRIVE
);
359 TRACE("%c:\n", 'A' + drive
);
360 DRIVE_CurDrive
= drive
;
361 if (pTask
) pTask
->curdrive
= drive
| 0x80;
362 chdir(DRIVE_GetUnixCwd(drive
));
367 /***********************************************************************
368 * DRIVE_FindDriveRoot
370 * Find a drive for which the root matches the beginning of the given path.
371 * This can be used to translate a Unix path into a drive + DOS path.
372 * Return value is the drive, or -1 on error. On success, path is modified
373 * to point to the beginning of the DOS path.
375 int DRIVE_FindDriveRoot( const char **path
)
377 /* Starting with the full path, check if the device and inode match any of
378 * the wine 'drives'. If not then remove the last path component and try
379 * again. If the last component was a '..' then skip a normal component
380 * since it's a directory that's ascended back out of.
382 int drive
, level
, len
;
383 char buffer
[MAX_PATHNAME_LEN
];
387 strcpy( buffer
, *path
);
388 while ((p
= strchr( buffer
, '\\' )) != NULL
)
390 len
= strlen(buffer
);
395 if (stat( buffer
, &st
) == 0 && S_ISDIR( st
.st_mode
))
397 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
399 if (!DOSDrives
[drive
].root
||
400 (DOSDrives
[drive
].flags
& DRIVE_DISABLED
))
403 if ((DOSDrives
[drive
].dev
== st
.st_dev
) &&
404 (DOSDrives
[drive
].ino
== st
.st_ino
))
406 TRACE( "%s -> drive %c:, root='%s', name='%s'\n",
407 *path
, 'A' + drive
, buffer
, *path
+ len
);
415 while (len
> 0 && level
< 1)
417 /* strip off a trailing slash */
418 while (len
> 0 && buffer
[len
- 1] == '/')
420 /* find start of the last path component */
421 while (len
> 0 && buffer
[len
- 1] != '/')
423 /* does removing it take us up a level? */
424 if (strcmp( buffer
+ len
, "." ) != 0)
425 level
+= strcmp( buffer
+ len
, ".." ) ? 1 : -1;
434 /***********************************************************************
437 const char * DRIVE_GetRoot( int drive
)
439 if (!DRIVE_IsValid( drive
)) return NULL
;
440 return DOSDrives
[drive
].root
;
444 /***********************************************************************
447 const char * DRIVE_GetDosCwd( int drive
)
449 TDB
*pTask
= TASK_GetCurrent();
450 if (!DRIVE_IsValid( drive
)) return NULL
;
452 /* Check if we need to change the directory to the new task. */
453 if (pTask
&& (pTask
->curdrive
& 0x80) && /* The task drive is valid */
454 ((pTask
->curdrive
& ~0x80) == drive
) && /* and it's the one we want */
455 (DRIVE_LastTask
!= GetCurrentTask())) /* and the task changed */
457 /* Perform the task-switch */
458 if (!DRIVE_Chdir( drive
, pTask
->curdir
)) DRIVE_Chdir( drive
, "\\" );
459 DRIVE_LastTask
= GetCurrentTask();
461 return DOSDrives
[drive
].dos_cwd
;
465 /***********************************************************************
468 const char * DRIVE_GetUnixCwd( int drive
)
470 TDB
*pTask
= TASK_GetCurrent();
471 if (!DRIVE_IsValid( drive
)) return NULL
;
473 /* Check if we need to change the directory to the new task. */
474 if (pTask
&& (pTask
->curdrive
& 0x80) && /* The task drive is valid */
475 ((pTask
->curdrive
& ~0x80) == drive
) && /* and it's the one we want */
476 (DRIVE_LastTask
!= GetCurrentTask())) /* and the task changed */
478 /* Perform the task-switch */
479 if (!DRIVE_Chdir( drive
, pTask
->curdir
)) DRIVE_Chdir( drive
, "\\" );
480 DRIVE_LastTask
= GetCurrentTask();
482 return DOSDrives
[drive
].unix_cwd
;
486 /***********************************************************************
489 const char * DRIVE_GetDevice( int drive
)
491 return (DRIVE_IsValid( drive
)) ? DOSDrives
[drive
].device
: NULL
;
494 /******************************************************************
495 * static WORD CDROM_Data_FindBestVoldesc
499 static WORD
CDROM_Data_FindBestVoldesc(int fd
)
501 BYTE cur_vd_type
, max_vd_type
= 0;
502 unsigned int offs
, best_offs
= 0, extra_offs
= 0;
505 for (offs
= 0x8000; offs
<= 0x9800; offs
+= 0x800)
507 /* if 'CDROM' occurs at position 8, this is a pre-iso9660 cd, and
508 * the volume label is displaced forward by 8
510 lseek(fd
, offs
+ 11, SEEK_SET
); /* check for non-ISO9660 signature */
512 if ((sig
[0] == 'R') && (sig
[1] == 'O') && (sig
[2]=='M'))
516 lseek(fd
, offs
+ extra_offs
, SEEK_SET
);
517 read(fd
, &cur_vd_type
, 1);
518 if (cur_vd_type
== 0xff) /* voldesc set terminator */
520 if (cur_vd_type
> max_vd_type
)
522 max_vd_type
= cur_vd_type
;
523 best_offs
= offs
+ extra_offs
;
529 /***********************************************************************
530 * DRIVE_ReadSuperblock
533 * DRIVE_SetLabel and DRIVE_SetSerialNumber use this in order
534 * to check, that they are writing on a FAT filesystem !
536 int DRIVE_ReadSuperblock (int drive
, char * buff
)
538 #define DRIVE_SUPER 96
543 if (memset(buff
,0,DRIVE_SUPER
)!=buff
) return -1;
544 if ((fd
=open(DOSDrives
[drive
].device
,O_RDONLY
)) == -1)
547 if (!DOSDrives
[drive
].device
)
548 ERR("No device configured for drive %c: !\n", 'A'+drive
);
550 ERR("Couldn't open device '%s' for drive %c: ! (%s)\n", DOSDrives
[drive
].device
, 'A'+drive
,
551 (stat(DOSDrives
[drive
].device
, &st
)) ?
552 "not available or symlink not valid ?" : "no permission");
553 ERR("Can't read drive volume info ! Either pre-set it or make sure the device to read it from is accessible !\n");
554 PROFILE_UsageWineIni();
558 switch(DOSDrives
[drive
].type
)
560 case DRIVE_REMOVABLE
:
565 offs
= CDROM_Data_FindBestVoldesc(fd
);
572 if ((offs
) && (lseek(fd
,offs
,SEEK_SET
)!=offs
))
577 if (read(fd
,buff
,DRIVE_SUPER
)!=DRIVE_SUPER
)
583 switch(DOSDrives
[drive
].type
)
585 case DRIVE_REMOVABLE
:
587 if ((buff
[0x26]!=0x29) || /* Check for FAT present */
588 /* FIXME: do really all FAT have their name beginning with
589 "FAT" ? (At least FAT12, FAT16 and FAT32 have :) */
590 memcmp( buff
+0x36,"FAT",3))
592 ERR("The filesystem is not FAT !! (device=%s)\n",
593 DOSDrives
[drive
].device
);
599 if (strncmp(&buff
[1],"CD001",5)) /* Check for iso9660 present */
604 /* FIXME: do we need to check for "CDROM", too ? (high sierra) */
618 /***********************************************************************
619 * DRIVE_WriteSuperblockEntry
622 * We are writing as little as possible (ie. not the whole SuperBlock)
623 * not to interfere with kernel. The drive can be mounted !
625 int DRIVE_WriteSuperblockEntry (int drive
, off_t ofs
, size_t len
, char * buff
)
629 if ((fd
=open(DOSDrives
[drive
].device
,O_WRONLY
))==-1)
631 ERR("Cannot open the device %s (for writing)\n",
632 DOSDrives
[drive
].device
);
635 if (lseek(fd
,ofs
,SEEK_SET
)!=ofs
)
637 ERR("lseek failed on device %s !\n",
638 DOSDrives
[drive
].device
);
642 if (write(fd
,buff
,len
)!=len
)
645 ERR("Cannot write on %s !\n",
646 DOSDrives
[drive
].device
);
652 /******************************************************************
653 * static HANDLE CDROM_Open
657 static HANDLE
CDROM_Open(int drive
)
661 strcpy(root
, "\\\\.\\A:");
664 return CreateFileA(root
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, 0);
667 /**************************************************************************
668 * CDROM_Data_GetLabel [internal]
670 DWORD
CDROM_Data_GetLabel(int drive
, char *label
)
672 #define LABEL_LEN 32+1
673 int dev
= open(DOSDrives
[drive
].device
, O_RDONLY
|O_NONBLOCK
);
674 WORD offs
= CDROM_Data_FindBestVoldesc(dev
);
675 WCHAR label_read
[LABEL_LEN
]; /* Unicode possible, too */
676 DWORD unicode_id
= 0;
680 if ((lseek(dev
, offs
+0x58, SEEK_SET
) == offs
+0x58)
681 && (read(dev
, &unicode_id
, 3) == 3))
683 int ver
= (unicode_id
& 0xff0000) >> 16;
685 if ((lseek(dev
, offs
+0x28, SEEK_SET
) != offs
+0x28)
686 || (read(dev
, &label_read
, LABEL_LEN
) != LABEL_LEN
))
690 if ((LOWORD(unicode_id
) == 0x2f25) /* Unicode ID */
691 && ((ver
== 0x40) || (ver
== 0x43) || (ver
== 0x45)))
692 { /* yippee, unicode */
695 for (i
=0; i
<LABEL_LEN
;i
++)
696 { /* Motorola -> Intel Unicode conversion :-\ */
698 label_read
[i
] = (ch
<< 8) | (ch
>> 8);
700 WideCharToMultiByte( CP_ACP
, 0, label_read
, -1, label
, 12, NULL
, NULL
);
705 strncpy(label
, (LPSTR
)label_read
, 11);
713 ERR("error reading label !\n");
717 /**************************************************************************
718 * CDROM_GetLabel [internal]
720 static DWORD
CDROM_GetLabel(int drive
, char *label
)
722 HANDLE h
= CDROM_Open(drive
);
727 if (!h
|| !DeviceIoControl(h
, IOCTL_CDROM_DISK_TYPE
, NULL
, 0, &cdd
, sizeof(cdd
), &br
, 0))
730 switch (cdd
.DiskData
& 0x03)
732 case CDROM_DISK_DATA_TRACK
:
733 if (!CDROM_Data_GetLabel(drive
, label
))
736 case CDROM_DISK_AUDIO_TRACK
:
737 strcpy(label
, "Audio CD ");
739 case CDROM_DISK_DATA_TRACK
|CDROM_DISK_AUDIO_TRACK
:
740 FIXME("Need to get the label of a mixed mode CD: not implemented yet !\n");
746 TRACE("CD: label is '%s'.\n", label
);
750 /***********************************************************************
753 const char * DRIVE_GetLabel( int drive
)
756 char buff
[DRIVE_SUPER
];
759 if (!DRIVE_IsValid( drive
)) return NULL
;
760 if (DOSDrives
[drive
].type
== DRIVE_CDROM
)
762 read
= CDROM_GetLabel(drive
, DOSDrives
[drive
].label_read
);
765 if (DOSDrives
[drive
].flags
& DRIVE_READ_VOL_INFO
)
767 if (DRIVE_ReadSuperblock(drive
,(char *) buff
))
768 ERR("Invalid or unreadable superblock on %s (%c:).\n",
769 DOSDrives
[drive
].device
, (char)(drive
+'A'));
771 if (DOSDrives
[drive
].type
== DRIVE_REMOVABLE
||
772 DOSDrives
[drive
].type
== DRIVE_FIXED
)
775 /* FIXME: ISO9660 uses a 32 bytes long label. Should we do also? */
776 if (offs
!= -1) memcpy(DOSDrives
[drive
].label_read
,buff
+offs
,11);
777 DOSDrives
[drive
].label_read
[11]='\0';
783 DOSDrives
[drive
].label_read
: DOSDrives
[drive
].label_conf
;
786 #define CDFRAMES_PERSEC 75
787 #define CDFRAMES_PERMIN (CDFRAMES_PERSEC * 60)
788 #define FRAME_OF_ADDR(a) ((a)[0] * CDFRAMES_PERMIN + (a)[1] * CDFRAMES_PERSEC + (a)[2])
789 #define FRAME_OF_TOC(toc, idx) FRAME_OF_ADDR((toc).TrackData[idx - (toc).FirstTrack].Address)
791 /**************************************************************************
792 * CDROM_Audio_GetSerial [internal]
794 static DWORD
CDROM_Audio_GetSerial(HANDLE h
)
796 unsigned long serial
= 0;
799 DWORD dwStart
, dwEnd
, br
;
802 if (!DeviceIoControl(h
, IOCTL_CDROM_READ_TOC
, NULL
, 0, &toc
, sizeof(toc
), &br
, 0))
806 * wMagic collects the wFrames from track 1
807 * dwStart, dwEnd collect the beginning and end of the disc respectively, in
809 * There it is collected for correcting the serial when there are less than
812 wMagic
= toc
.TrackData
[0].Address
[2];
813 dwStart
= FRAME_OF_TOC(toc
, toc
.FirstTrack
);
815 for (i
= 0; i
<= toc
.LastTrack
- toc
.FirstTrack
; i
++) {
816 serial
+= (toc
.TrackData
[i
].Address
[0] << 16) |
817 (toc
.TrackData
[i
].Address
[1] << 8) | toc
.TrackData
[i
].Address
[2];
819 dwEnd
= FRAME_OF_TOC(toc
, toc
.LastTrack
+ 1);
821 if (toc
.LastTrack
- toc
.FirstTrack
+ 1 < 3)
822 serial
+= wMagic
+ (dwEnd
- dwStart
);
827 /**************************************************************************
828 * CDROM_Data_GetSerial [internal]
830 static DWORD
CDROM_Data_GetSerial(int drive
)
832 int dev
= open(DOSDrives
[drive
].device
, O_RDONLY
|O_NONBLOCK
);
838 BYTE b0
= 0, b1
= 1, b2
= 2, b3
= 3;
841 if (dev
== -1) return 0;
842 offs
= CDROM_Data_FindBestVoldesc(dev
);
851 lseek(dev
, offs
, SEEK_SET
);
852 read(dev
, buf
, 2048);
854 * OK, another braindead one... argh. Just believe it.
855 * Me$$ysoft chose to reverse the serial number in NT4/W2K.
856 * It's true and nobody will ever be able to change it.
858 ovi
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOA
);
860 if ((ovi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) && (ovi
.dwMajorVersion
>= 4))
862 b0
= 3; b1
= 2; b2
= 1; b3
= 0;
864 for (i
= 0; i
< 2048; i
+= 4)
866 /* DON'T optimize this into DWORD !! (breaks overflow) */
867 serial
.p
[b0
] += buf
[i
+b0
];
868 serial
.p
[b1
] += buf
[i
+b1
];
869 serial
.p
[b2
] += buf
[i
+b2
];
870 serial
.p
[b3
] += buf
[i
+b3
];
877 /**************************************************************************
878 * CDROM_GetSerial [internal]
880 static DWORD
CDROM_GetSerial(int drive
)
883 HANDLE h
= CDROM_Open(drive
);
887 if (!h
|| ! !DeviceIoControl(h
, IOCTL_CDROM_DISK_TYPE
, NULL
, 0, &cdd
, sizeof(cdd
), &br
, 0))
890 switch (cdd
.DiskData
& 0x03)
892 case CDROM_DISK_DATA_TRACK
:
893 /* hopefully a data CD */
894 serial
= CDROM_Data_GetSerial(drive
);
896 case CDROM_DISK_AUDIO_TRACK
:
898 case CDROM_DISK_DATA_TRACK
|CDROM_DISK_AUDIO_TRACK
:
899 serial
= CDROM_Audio_GetSerial(h
);
906 TRACE("CD serial number is %04x-%04x.\n", HIWORD(serial
), LOWORD(serial
));
913 /***********************************************************************
914 * DRIVE_GetSerialNumber
916 DWORD
DRIVE_GetSerialNumber( int drive
)
919 char buff
[DRIVE_SUPER
];
921 if (!DRIVE_IsValid( drive
)) return 0;
923 if (DOSDrives
[drive
].flags
& DRIVE_READ_VOL_INFO
)
925 switch(DOSDrives
[drive
].type
)
927 case DRIVE_REMOVABLE
:
929 if (DRIVE_ReadSuperblock(drive
,(char *) buff
))
930 MESSAGE("Invalid or unreadable superblock on %s (%c:)."
931 " Maybe not FAT?\n" ,
932 DOSDrives
[drive
].device
, 'A'+drive
);
934 serial
= *((DWORD
*)(buff
+0x27));
937 serial
= CDROM_GetSerial(drive
);
940 FIXME("Serial number reading from file system on drive %c: not supported yet.\n", drive
+'A');
944 return (serial
) ? serial
: DOSDrives
[drive
].serial_conf
;
948 /***********************************************************************
949 * DRIVE_SetSerialNumber
951 int DRIVE_SetSerialNumber( int drive
, DWORD serial
)
953 char buff
[DRIVE_SUPER
];
955 if (!DRIVE_IsValid( drive
)) return 0;
957 if (DOSDrives
[drive
].flags
& DRIVE_READ_VOL_INFO
)
959 if ((DOSDrives
[drive
].type
!= DRIVE_REMOVABLE
) &&
960 (DOSDrives
[drive
].type
!= DRIVE_FIXED
)) return 0;
961 /* check, if the drive has a FAT filesystem */
962 if (DRIVE_ReadSuperblock(drive
, buff
)) return 0;
963 if (DRIVE_WriteSuperblockEntry(drive
, 0x27, 4, (char *) &serial
)) return 0;
967 if (DOSDrives
[drive
].type
== DRIVE_CDROM
) return 0;
968 DOSDrives
[drive
].serial_conf
= serial
;
973 /***********************************************************************
976 static UINT
DRIVE_GetType( int drive
)
978 if (!DRIVE_IsValid( drive
)) return DRIVE_UNKNOWN
;
979 return DOSDrives
[drive
].type
;
983 /***********************************************************************
986 UINT
DRIVE_GetFlags( int drive
)
988 if ((drive
< 0) || (drive
>= MAX_DOS_DRIVES
)) return 0;
989 return DOSDrives
[drive
].flags
;
993 /***********************************************************************
996 int DRIVE_Chdir( int drive
, const char *path
)
998 DOS_FULL_NAME full_name
;
999 char buffer
[MAX_PATHNAME_LEN
];
1001 BY_HANDLE_FILE_INFORMATION info
;
1002 TDB
*pTask
= TASK_GetCurrent();
1004 strcpy( buffer
, "A:" );
1006 TRACE("(%s,%s)\n", buffer
, path
);
1007 lstrcpynA( buffer
+ 2, path
, sizeof(buffer
) - 2 );
1009 if (!DOSFS_GetFullName( buffer
, TRUE
, &full_name
)) return 0;
1010 if (!FILE_Stat( full_name
.long_name
, &info
)) return 0;
1011 if (!(info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
))
1013 SetLastError( ERROR_FILE_NOT_FOUND
);
1016 unix_cwd
= full_name
.long_name
+ strlen( DOSDrives
[drive
].root
);
1017 while (*unix_cwd
== '/') unix_cwd
++;
1019 TRACE("(%c:): unix_cwd=%s dos_cwd=%s\n",
1020 'A' + drive
, unix_cwd
, full_name
.short_name
+ 3 );
1022 HeapFree( GetProcessHeap(), 0, DOSDrives
[drive
].dos_cwd
);
1023 HeapFree( GetProcessHeap(), 0, DOSDrives
[drive
].unix_cwd
);
1024 DOSDrives
[drive
].dos_cwd
= heap_strdup( full_name
.short_name
+ 3 );
1025 DOSDrives
[drive
].unix_cwd
= heap_strdup( unix_cwd
);
1027 if (pTask
&& (pTask
->curdrive
& 0x80) &&
1028 ((pTask
->curdrive
& ~0x80) == drive
))
1030 lstrcpynA( pTask
->curdir
, full_name
.short_name
+ 2,
1031 sizeof(pTask
->curdir
) );
1032 DRIVE_LastTask
= GetCurrentTask();
1033 chdir(unix_cwd
); /* Only change if on current drive */
1039 /***********************************************************************
1042 int DRIVE_Disable( int drive
)
1044 if ((drive
< 0) || (drive
>= MAX_DOS_DRIVES
) || !DOSDrives
[drive
].root
)
1046 SetLastError( ERROR_INVALID_DRIVE
);
1049 DOSDrives
[drive
].flags
|= DRIVE_DISABLED
;
1054 /***********************************************************************
1057 int DRIVE_Enable( int drive
)
1059 if ((drive
< 0) || (drive
>= MAX_DOS_DRIVES
) || !DOSDrives
[drive
].root
)
1061 SetLastError( ERROR_INVALID_DRIVE
);
1064 DOSDrives
[drive
].flags
&= ~DRIVE_DISABLED
;
1069 /***********************************************************************
1070 * DRIVE_SetLogicalMapping
1072 int DRIVE_SetLogicalMapping ( int existing_drive
, int new_drive
)
1074 /* If new_drive is already valid, do nothing and return 0
1075 otherwise, copy DOSDrives[existing_drive] to DOSDrives[new_drive] */
1077 DOSDRIVE
*old
, *new;
1079 old
= DOSDrives
+ existing_drive
;
1080 new = DOSDrives
+ new_drive
;
1082 if ((existing_drive
< 0) || (existing_drive
>= MAX_DOS_DRIVES
) ||
1084 (new_drive
< 0) || (new_drive
>= MAX_DOS_DRIVES
))
1086 SetLastError( ERROR_INVALID_DRIVE
);
1092 TRACE("Can't map drive %c: to already existing drive %c:\n",
1093 'A' + existing_drive
, 'A' + new_drive
);
1094 /* it is already mapped there, so return success */
1095 if (!strcmp(old
->root
,new->root
))
1100 new->root
= heap_strdup( old
->root
);
1101 new->dos_cwd
= heap_strdup( old
->dos_cwd
);
1102 new->unix_cwd
= heap_strdup( old
->unix_cwd
);
1103 new->device
= heap_strdup( old
->device
);
1104 memcpy ( new->label_conf
, old
->label_conf
, 12 );
1105 memcpy ( new->label_read
, old
->label_read
, 12 );
1106 new->serial_conf
= old
->serial_conf
;
1107 new->type
= old
->type
;
1108 new->flags
= old
->flags
;
1109 new->dev
= old
->dev
;
1110 new->ino
= old
->ino
;
1112 TRACE("Drive %c: is now equal to drive %c:\n",
1113 'A' + new_drive
, 'A' + existing_drive
);
1119 /***********************************************************************
1122 * Open the drive raw device and return a Unix fd (or -1 on error).
1124 int DRIVE_OpenDevice( int drive
, int flags
)
1126 if (!DRIVE_IsValid( drive
)) return -1;
1127 return open( DOSDrives
[drive
].device
, flags
);
1131 /***********************************************************************
1134 * Read raw sectors from a device
1136 int DRIVE_RawRead(BYTE drive
, DWORD begin
, DWORD nr_sect
, BYTE
*dataptr
, BOOL fake_success
)
1140 if ((fd
= DRIVE_OpenDevice( drive
, O_RDONLY
)) != -1)
1142 lseek( fd
, begin
* 512, SEEK_SET
);
1143 /* FIXME: check errors */
1144 read( fd
, dataptr
, nr_sect
* 512 );
1149 memset(dataptr
, 0, nr_sect
* 512);
1152 if (begin
== 0 && nr_sect
> 1) *(dataptr
+ 512) = 0xf8;
1153 if (begin
== 1) *dataptr
= 0xf8;
1162 /***********************************************************************
1165 * Write raw sectors to a device
1167 int DRIVE_RawWrite(BYTE drive
, DWORD begin
, DWORD nr_sect
, BYTE
*dataptr
, BOOL fake_success
)
1171 if ((fd
= DRIVE_OpenDevice( drive
, O_RDONLY
)) != -1)
1173 lseek( fd
, begin
* 512, SEEK_SET
);
1174 /* FIXME: check errors */
1175 write( fd
, dataptr
, nr_sect
* 512 );
1179 if (!(fake_success
))
1186 /***********************************************************************
1187 * DRIVE_GetFreeSpace
1189 static int DRIVE_GetFreeSpace( int drive
, PULARGE_INTEGER size
,
1190 PULARGE_INTEGER available
)
1194 if (!DRIVE_IsValid(drive
))
1196 SetLastError( ERROR_INVALID_DRIVE
);
1200 /* FIXME: add autoconf check for this */
1201 #if defined(__svr4__) || defined(_SCO_DS) || defined(__sun)
1202 if (statfs( DOSDrives
[drive
].root
, &info
, 0, 0) < 0)
1204 if (statfs( DOSDrives
[drive
].root
, &info
) < 0)
1208 WARN("cannot do statfs(%s)\n", DOSDrives
[drive
].root
);
1212 size
->QuadPart
= RtlEnlargedUnsignedMultiply( info
.f_bsize
, info
.f_blocks
);
1213 #ifdef STATFS_HAS_BAVAIL
1214 available
->QuadPart
= RtlEnlargedUnsignedMultiply( info
.f_bavail
, info
.f_bsize
);
1216 # ifdef STATFS_HAS_BFREE
1217 available
->QuadPart
= RtlEnlargedUnsignedMultiply( info
.f_bfree
, info
.f_bsize
);
1219 # error "statfs has no bfree/bavail member!"
1222 if (DOSDrives
[drive
].type
== DRIVE_CDROM
)
1223 { /* ALWAYS 0, even if no real CD-ROM mounted there !! */
1224 available
->QuadPart
= 0;
1229 /***********************************************************************
1230 * DRIVE_GetCurrentDirectory
1231 * Returns "X:\\path\\etc\\".
1233 * Despite the API description, return required length including the
1234 * terminating null when buffer too small. This is the real behaviour.
1237 static UINT
DRIVE_GetCurrentDirectory( UINT buflen
, LPSTR buf
)
1240 const char *s
= DRIVE_GetDosCwd( DRIVE_GetCurrentDrive() );
1243 ret
= strlen(s
) + 3; /* length of WHOLE current directory */
1244 if (ret
>= buflen
) return ret
+ 1;
1245 lstrcpynA( buf
, "A:\\", min( 4u, buflen
) );
1246 if (buflen
) buf
[0] += DRIVE_GetCurrentDrive();
1247 if (buflen
> 3) lstrcpynA( buf
+ 3, s
, buflen
- 3 );
1252 /***********************************************************************
1255 * Build the environment array containing the drives' current directories.
1256 * Resulting pointer must be freed with HeapFree.
1258 char *DRIVE_BuildEnv(void)
1261 const char *cwd
[MAX_DOS_DRIVES
];
1264 for (i
= 0; i
< MAX_DOS_DRIVES
; i
++)
1266 if ((cwd
[i
] = DRIVE_GetDosCwd(i
)) && cwd
[i
][0]) length
+= strlen(cwd
[i
]) + 8;
1268 if (!(env
= HeapAlloc( GetProcessHeap(), 0, length
+1 ))) return NULL
;
1269 for (i
= 0, p
= env
; i
< MAX_DOS_DRIVES
; i
++)
1271 if (cwd
[i
] && cwd
[i
][0])
1272 p
+= sprintf( p
, "=%c:=%c:\\%s", 'A'+i
, 'A'+i
, cwd
[i
] ) + 1;
1279 /***********************************************************************
1280 * GetDiskFreeSpace (KERNEL.422)
1282 BOOL16 WINAPI
GetDiskFreeSpace16( LPCSTR root
, LPDWORD cluster_sectors
,
1283 LPDWORD sector_bytes
, LPDWORD free_clusters
,
1284 LPDWORD total_clusters
)
1286 return GetDiskFreeSpaceA( root
, cluster_sectors
, sector_bytes
,
1287 free_clusters
, total_clusters
);
1291 /***********************************************************************
1292 * GetDiskFreeSpaceA (KERNEL32.@)
1294 * Fails if expression resulting from current drive's dir and "root"
1295 * is not a root dir of the target drive.
1297 * UNDOC: setting some LPDWORDs to NULL is perfectly possible
1298 * if the corresponding info is unneeded.
1300 * FIXME: needs to support UNC names from Win95 OSR2 on.
1302 * Behaviour under Win95a:
1303 * CurrDir root result
1304 * "E:\\TEST" "E:" FALSE
1308 * "E:\\TEST" "\\" TRUE
1309 * "E:\\TEST" ":\\" FALSE
1310 * "E:\\TEST" "E:\\" TRUE
1311 * "E:\\TEST" "" FALSE
1312 * "E:\\" "" FALSE (!)
1314 * "E:\\TEST" 0x0 TRUE (!)
1315 * "E:\\TEST" "C:" TRUE (when CurrDir of "C:" set to "\\")
1316 * "E:\\TEST" "C:" FALSE (when CurrDir of "C:" set to "\\TEST")
1318 BOOL WINAPI
GetDiskFreeSpaceA( LPCSTR root
, LPDWORD cluster_sectors
,
1319 LPDWORD sector_bytes
, LPDWORD free_clusters
,
1320 LPDWORD total_clusters
)
1322 int drive
, sec_size
;
1323 ULARGE_INTEGER size
,available
;
1327 if ((!root
) || (strcmp(root
,"\\") == 0))
1328 drive
= DRIVE_GetCurrentDrive();
1330 if ( (strlen(root
) >= 2) && (root
[1] == ':')) /* root contains drive tag */
1332 drive
= toupper(root
[0]) - 'A';
1334 if (path
[0] == '\0')
1335 path
= DRIVE_GetDosCwd(drive
);
1337 if (path
[0] == '\\')
1339 if (path
[0]) /* oops, we are in a subdir */
1341 SetLastError(ERROR_INVALID_NAME
);
1347 SetLastError(ERROR_INVALID_NAME
);
1351 if (!DRIVE_GetFreeSpace(drive
, &size
, &available
)) return FALSE
;
1353 /* Cap the size and available at 2GB as per specs. */
1354 if ((size
.s
.HighPart
) ||(size
.s
.LowPart
> 0x7fffffff))
1356 size
.s
.HighPart
= 0;
1357 size
.s
.LowPart
= 0x7fffffff;
1359 if ((available
.s
.HighPart
) ||(available
.s
.LowPart
> 0x7fffffff))
1361 available
.s
.HighPart
=0;
1362 available
.s
.LowPart
= 0x7fffffff;
1364 sec_size
= (DRIVE_GetType(drive
)==DRIVE_CDROM
) ? 2048 : 512;
1365 size
.s
.LowPart
/= sec_size
;
1366 available
.s
.LowPart
/= sec_size
;
1367 /* FIXME: probably have to adjust those variables too for CDFS */
1369 while (cluster_sec
* 65536 < size
.s
.LowPart
) cluster_sec
*= 2;
1371 if (cluster_sectors
)
1372 *cluster_sectors
= cluster_sec
;
1374 *sector_bytes
= sec_size
;
1376 *free_clusters
= available
.s
.LowPart
/ cluster_sec
;
1378 *total_clusters
= size
.s
.LowPart
/ cluster_sec
;
1383 /***********************************************************************
1384 * GetDiskFreeSpaceW (KERNEL32.@)
1386 BOOL WINAPI
GetDiskFreeSpaceW( LPCWSTR root
, LPDWORD cluster_sectors
,
1387 LPDWORD sector_bytes
, LPDWORD free_clusters
,
1388 LPDWORD total_clusters
)
1393 xroot
= HEAP_strdupWtoA( GetProcessHeap(), 0, root
);
1394 ret
= GetDiskFreeSpaceA( xroot
,cluster_sectors
, sector_bytes
,
1395 free_clusters
, total_clusters
);
1396 HeapFree( GetProcessHeap(), 0, xroot
);
1401 /***********************************************************************
1402 * GetDiskFreeSpaceExA (KERNEL32.@)
1404 * This function is used to acquire the size of the available and
1405 * total space on a logical volume.
1409 * Zero on failure, nonzero upon success. Use GetLastError to obtain
1410 * detailed error information.
1413 BOOL WINAPI
GetDiskFreeSpaceExA( LPCSTR root
,
1414 PULARGE_INTEGER avail
,
1415 PULARGE_INTEGER total
,
1416 PULARGE_INTEGER totalfree
)
1419 ULARGE_INTEGER size
,available
;
1421 if (!root
) drive
= DRIVE_GetCurrentDrive();
1423 { /* C: always works for GetDiskFreeSpaceEx */
1424 if ((root
[1]) && ((root
[1] != ':') || (root
[2] && root
[2] != '\\')))
1426 FIXME("there are valid root names which are not supported yet\n");
1427 /* ..like UNC names, for instance. */
1429 WARN("invalid root '%s'\n", root
);
1432 drive
= toupper(root
[0]) - 'A';
1435 if (!DRIVE_GetFreeSpace(drive
, &size
, &available
)) return FALSE
;
1439 total
->s
.HighPart
= size
.s
.HighPart
;
1440 total
->s
.LowPart
= size
.s
.LowPart
;
1445 totalfree
->s
.HighPart
= available
.s
.HighPart
;
1446 totalfree
->s
.LowPart
= available
.s
.LowPart
;
1451 if (FIXME_ON(dosfs
))
1453 /* On Windows2000, we need to check the disk quota
1454 allocated for the user owning the calling process. We
1455 don't want to be more obtrusive than necessary with the
1456 FIXME messages, so don't print the FIXME unless Wine is
1457 actually masquerading as Windows2000. */
1460 ovi
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOA
);
1461 if (GetVersionExA(&ovi
))
1463 if (ovi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
&& ovi
.dwMajorVersion
> 4)
1464 FIXME("no per-user quota support yet\n");
1468 /* Quick hack, should eventually be fixed to work 100% with
1469 Windows2000 (see comment above). */
1470 avail
->s
.HighPart
= available
.s
.HighPart
;
1471 avail
->s
.LowPart
= available
.s
.LowPart
;
1477 /***********************************************************************
1478 * GetDiskFreeSpaceExW (KERNEL32.@)
1480 BOOL WINAPI
GetDiskFreeSpaceExW( LPCWSTR root
, PULARGE_INTEGER avail
,
1481 PULARGE_INTEGER total
,
1482 PULARGE_INTEGER totalfree
)
1487 xroot
= HEAP_strdupWtoA( GetProcessHeap(), 0, root
);
1488 ret
= GetDiskFreeSpaceExA( xroot
, avail
, total
, totalfree
);
1489 HeapFree( GetProcessHeap(), 0, xroot
);
1493 /***********************************************************************
1494 * GetDriveType (KERNEL.136)
1495 * This function returns the type of a drive in Win16.
1496 * Note that it returns DRIVE_REMOTE for CD-ROMs, since MSCDEX uses the
1497 * remote drive API. The return value DRIVE_REMOTE for CD-ROMs has been
1498 * verified on Win 3.11 and Windows 95. Some programs rely on it, so don't
1499 * do any pseudo-clever changes.
1502 * drivetype DRIVE_xxx
1504 UINT16 WINAPI
GetDriveType16( UINT16 drive
) /* [in] number (NOT letter) of drive */
1506 UINT type
= DRIVE_GetType(drive
);
1507 TRACE("(%c:)\n", 'A' + drive
);
1508 if (type
== DRIVE_CDROM
) type
= DRIVE_REMOTE
;
1513 /***********************************************************************
1514 * GetDriveTypeA (KERNEL32.@)
1516 * Returns the type of the disk drive specified. If root is NULL the
1517 * root of the current directory is used.
1521 * Type of drive (from Win32 SDK):
1523 * DRIVE_UNKNOWN unable to find out anything about the drive
1524 * DRIVE_NO_ROOT_DIR nonexistent root dir
1525 * DRIVE_REMOVABLE the disk can be removed from the machine
1526 * DRIVE_FIXED the disk can not be removed from the machine
1527 * DRIVE_REMOTE network disk
1528 * DRIVE_CDROM CDROM drive
1529 * DRIVE_RAMDISK virtual disk in RAM
1531 UINT WINAPI
GetDriveTypeA(LPCSTR root
) /* [in] String describing drive */
1534 TRACE("(%s)\n", debugstr_a(root
));
1536 if (NULL
== root
) drive
= DRIVE_GetCurrentDrive();
1539 if ((root
[1]) && (root
[1] != ':'))
1541 WARN("invalid root %s\n", debugstr_a(root
));
1542 return DRIVE_NO_ROOT_DIR
;
1544 drive
= toupper(root
[0]) - 'A';
1546 return DRIVE_GetType(drive
);
1550 /***********************************************************************
1551 * GetDriveTypeW (KERNEL32.@)
1553 UINT WINAPI
GetDriveTypeW( LPCWSTR root
)
1555 LPSTR xpath
= HEAP_strdupWtoA( GetProcessHeap(), 0, root
);
1556 UINT ret
= GetDriveTypeA( xpath
);
1557 HeapFree( GetProcessHeap(), 0, xpath
);
1562 /***********************************************************************
1563 * GetCurrentDirectory (KERNEL.411)
1565 UINT16 WINAPI
GetCurrentDirectory16( UINT16 buflen
, LPSTR buf
)
1567 return (UINT16
)DRIVE_GetCurrentDirectory(buflen
, buf
);
1571 /***********************************************************************
1572 * GetCurrentDirectoryA (KERNEL32.@)
1574 UINT WINAPI
GetCurrentDirectoryA( UINT buflen
, LPSTR buf
)
1577 char longname
[MAX_PATHNAME_LEN
];
1578 char shortname
[MAX_PATHNAME_LEN
];
1579 ret
= DRIVE_GetCurrentDirectory(MAX_PATHNAME_LEN
, shortname
);
1580 if ( ret
> MAX_PATHNAME_LEN
) {
1581 ERR_(file
)("pathnamelength (%d) > MAX_PATHNAME_LEN!\n", ret
);
1584 GetLongPathNameA(shortname
, longname
, MAX_PATHNAME_LEN
);
1585 ret
= strlen( longname
) + 1;
1586 if (ret
> buflen
) return ret
;
1587 strcpy(buf
, longname
);
1591 /***********************************************************************
1592 * GetCurrentDirectoryW (KERNEL32.@)
1594 UINT WINAPI
GetCurrentDirectoryW( UINT buflen
, LPWSTR buf
)
1596 LPSTR xpath
= HeapAlloc( GetProcessHeap(), 0, buflen
+1 );
1597 UINT ret
= GetCurrentDirectoryA( buflen
, xpath
);
1598 if (ret
< buflen
) ret
= MultiByteToWideChar( CP_ACP
, 0, xpath
, -1, buf
, buflen
) - 1;
1599 HeapFree( GetProcessHeap(), 0, xpath
);
1604 /***********************************************************************
1605 * SetCurrentDirectory (KERNEL.412)
1607 BOOL16 WINAPI
SetCurrentDirectory16( LPCSTR dir
)
1609 return SetCurrentDirectoryA( dir
);
1613 /***********************************************************************
1614 * SetCurrentDirectoryA (KERNEL32.@)
1616 BOOL WINAPI
SetCurrentDirectoryA( LPCSTR dir
)
1618 int drive
, olddrive
= DRIVE_GetCurrentDrive();
1621 ERR_(file
)("(NULL)!\n");
1624 if (dir
[0] && (dir
[1]==':'))
1626 drive
= toupper( *dir
) - 'A';
1632 /* WARNING: we need to set the drive before the dir, as DRIVE_Chdir
1633 sets pTask->curdir only if pTask->curdrive is drive */
1634 if (!(DRIVE_SetCurrentDrive( drive
)))
1636 /* FIXME: what about empty strings? Add a \\ ? */
1637 if (!DRIVE_Chdir( drive
, dir
)) {
1638 DRIVE_SetCurrentDrive(olddrive
);
1645 /***********************************************************************
1646 * SetCurrentDirectoryW (KERNEL32.@)
1648 BOOL WINAPI
SetCurrentDirectoryW( LPCWSTR dirW
)
1650 LPSTR dir
= HEAP_strdupWtoA( GetProcessHeap(), 0, dirW
);
1651 BOOL res
= SetCurrentDirectoryA( dir
);
1652 HeapFree( GetProcessHeap(), 0, dir
);
1657 /***********************************************************************
1658 * GetLogicalDriveStringsA (KERNEL32.@)
1660 UINT WINAPI
GetLogicalDriveStringsA( UINT len
, LPSTR buffer
)
1664 for (drive
= count
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
1665 if (DRIVE_IsValid(drive
)) count
++;
1666 if ((count
* 4) + 1 <= len
)
1669 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
1670 if (DRIVE_IsValid(drive
))
1681 return (count
* 4) + 1; /* account for terminating null */
1682 /* The API tells about these different return values */
1686 /***********************************************************************
1687 * GetLogicalDriveStringsW (KERNEL32.@)
1689 UINT WINAPI
GetLogicalDriveStringsW( UINT len
, LPWSTR buffer
)
1693 for (drive
= count
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
1694 if (DRIVE_IsValid(drive
)) count
++;
1695 if (count
* 4 * sizeof(WCHAR
) <= len
)
1698 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
1699 if (DRIVE_IsValid(drive
))
1701 *p
++ = (WCHAR
)('a' + drive
);
1708 return count
* 4 * sizeof(WCHAR
);
1712 /***********************************************************************
1713 * GetLogicalDrives (KERNEL32.@)
1715 DWORD WINAPI
GetLogicalDrives(void)
1720 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
1722 if ( (DRIVE_IsValid(drive
)) ||
1723 (DOSDrives
[drive
].type
== DRIVE_CDROM
)) /* audio CD is also valid */
1724 ret
|= (1 << drive
);
1730 /***********************************************************************
1731 * GetVolumeInformationA (KERNEL32.@)
1733 BOOL WINAPI
GetVolumeInformationA( LPCSTR root
, LPSTR label
,
1734 DWORD label_len
, DWORD
*serial
,
1735 DWORD
*filename_len
, DWORD
*flags
,
1736 LPSTR fsname
, DWORD fsname_len
)
1741 /* FIXME, SetLastError()s missing */
1743 if (!root
) drive
= DRIVE_GetCurrentDrive();
1746 if ((root
[1]) && (root
[1] != ':'))
1748 WARN("invalid root '%s'\n",root
);
1751 drive
= toupper(root
[0]) - 'A';
1753 if (!DRIVE_IsValid( drive
)) return FALSE
;
1756 lstrcpynA( label
, DRIVE_GetLabel(drive
), label_len
);
1757 cp
= label
+ strlen(label
);
1758 while (cp
!= label
&& *(cp
-1) == ' ') cp
--;
1761 if (serial
) *serial
= DRIVE_GetSerialNumber(drive
);
1763 /* Set the filesystem information */
1764 /* Note: we only emulate a FAT fs at present */
1767 if (DOSDrives
[drive
].flags
& DRIVE_SHORT_NAMES
)
1770 *filename_len
= 255;
1775 if (DOSDrives
[drive
].flags
& DRIVE_CASE_SENSITIVE
)
1776 *flags
|=FS_CASE_SENSITIVE
;
1777 if (DOSDrives
[drive
].flags
& DRIVE_CASE_PRESERVING
)
1778 *flags
|=FS_CASE_IS_PRESERVED
;
1781 /* Diablo checks that return code ... */
1782 if (DOSDrives
[drive
].type
== DRIVE_CDROM
)
1783 lstrcpynA( fsname
, "CDFS", fsname_len
);
1785 lstrcpynA( fsname
, "FAT", fsname_len
);
1791 /***********************************************************************
1792 * GetVolumeInformationW (KERNEL32.@)
1794 BOOL WINAPI
GetVolumeInformationW( LPCWSTR root
, LPWSTR label
,
1795 DWORD label_len
, DWORD
*serial
,
1796 DWORD
*filename_len
, DWORD
*flags
,
1797 LPWSTR fsname
, DWORD fsname_len
)
1799 LPSTR xroot
= HEAP_strdupWtoA( GetProcessHeap(), 0, root
);
1800 LPSTR xvolname
= label
? HeapAlloc(GetProcessHeap(),0,label_len
) : NULL
;
1801 LPSTR xfsname
= fsname
? HeapAlloc(GetProcessHeap(),0,fsname_len
) : NULL
;
1802 BOOL ret
= GetVolumeInformationA( xroot
, xvolname
, label_len
, serial
,
1803 filename_len
, flags
, xfsname
,
1807 if (label
) MultiByteToWideChar( CP_ACP
, 0, xvolname
, -1, label
, label_len
);
1808 if (fsname
) MultiByteToWideChar( CP_ACP
, 0, xfsname
, -1, fsname
, fsname_len
);
1810 HeapFree( GetProcessHeap(), 0, xroot
);
1811 HeapFree( GetProcessHeap(), 0, xvolname
);
1812 HeapFree( GetProcessHeap(), 0, xfsname
);
1816 /***********************************************************************
1817 * SetVolumeLabelA (KERNEL32.@)
1819 BOOL WINAPI
SetVolumeLabelA( LPCSTR root
, LPCSTR volname
)
1823 /* FIXME, SetLastErrors missing */
1825 if (!root
) drive
= DRIVE_GetCurrentDrive();
1828 if ((root
[1]) && (root
[1] != ':'))
1830 WARN("invalid root '%s'\n",root
);
1833 drive
= toupper(root
[0]) - 'A';
1835 if (!DRIVE_IsValid( drive
)) return FALSE
;
1837 /* some copy protection stuff check this */
1838 if (DOSDrives
[drive
].type
== DRIVE_CDROM
) return FALSE
;
1840 FIXME("(%s,%s),stub!\n", root
, volname
);
1844 /***********************************************************************
1845 * SetVolumeLabelW (KERNEL32.@)
1847 BOOL WINAPI
SetVolumeLabelW(LPCWSTR rootpath
,LPCWSTR volname
)
1852 xroot
= HEAP_strdupWtoA( GetProcessHeap(), 0, rootpath
);
1853 xvol
= HEAP_strdupWtoA( GetProcessHeap(), 0, volname
);
1854 ret
= SetVolumeLabelA( xroot
, xvol
);
1855 HeapFree( GetProcessHeap(), 0, xroot
);
1856 HeapFree( GetProcessHeap(), 0, xvol
);