2 * DOS drives handling functions
4 * Copyright 1993 Erik Bos
5 * Copyright 1996 Alexandre Julliard
14 #include <sys/types.h>
20 #ifdef HAVE_SYS_PARAM_H
21 # include <sys/param.h>
23 #ifdef STATFS_DEFINED_BY_SYS_VFS
26 # ifdef STATFS_DEFINED_BY_SYS_MOUNT
27 # include <sys/mount.h>
29 # ifdef STATFS_DEFINED_BY_SYS_STATFS
30 # include <sys/statfs.h>
36 #include "wine/winbase16.h" /* for GetCurrentTask */
37 #include "wine/winestring.h" /* for lstrcpyAtoW */
44 #include "wine/port.h"
46 #include "debugtools.h"
48 DEFAULT_DEBUG_CHANNEL(dosfs
)
49 DECLARE_DEBUG_CHANNEL(file
)
53 char *root
; /* root dir in Unix format without trailing / */
54 char *dos_cwd
; /* cwd in DOS format without leading or trailing \ */
55 char *unix_cwd
; /* cwd in Unix format without leading or trailing / */
56 char *device
; /* raw device path */
57 char label
[12]; /* drive label */
58 DWORD serial
; /* drive serial number */
59 DRIVETYPE type
; /* drive type */
60 UINT flags
; /* drive flags */
61 dev_t dev
; /* unix device number */
62 ino_t ino
; /* unix inode number */
66 static const char * const DRIVE_Types
[] =
68 "floppy", /* TYPE_FLOPPY */
70 "cdrom", /* TYPE_CDROM */
71 "network" /* TYPE_NETWORK */
75 /* Known filesystem types */
83 static const FS_DESCR DRIVE_Filesystems
[] =
85 { "unix", DRIVE_CASE_SENSITIVE
| DRIVE_CASE_PRESERVING
},
86 { "msdos", DRIVE_SHORT_NAMES
},
87 { "dos", DRIVE_SHORT_NAMES
},
88 { "fat", DRIVE_SHORT_NAMES
},
89 { "vfat", DRIVE_CASE_PRESERVING
},
90 { "win95", DRIVE_CASE_PRESERVING
},
95 static DOSDRIVE DOSDrives
[MAX_DOS_DRIVES
];
96 static int DRIVE_CurDrive
= -1;
98 static HTASK16 DRIVE_LastTask
= 0;
101 /***********************************************************************
104 static DRIVETYPE
DRIVE_GetDriveType( const char *name
)
109 PROFILE_GetWineIniString( name
, "Type", "hd", buffer
, sizeof(buffer
) );
110 for (i
= 0; i
< sizeof(DRIVE_Types
)/sizeof(DRIVE_Types
[0]); i
++)
112 if (!strcasecmp( buffer
, DRIVE_Types
[i
] )) return (DRIVETYPE
)i
;
114 MESSAGE("%s: unknown type '%s', defaulting to 'hd'.\n", name
, buffer
);
119 /***********************************************************************
122 static UINT
DRIVE_GetFSFlags( const char *name
, const char *value
)
124 const FS_DESCR
*descr
;
126 for (descr
= DRIVE_Filesystems
; descr
->name
; descr
++)
127 if (!strcasecmp( value
, descr
->name
)) return descr
->flags
;
128 MESSAGE("%s: unknown filesystem type '%s', defaulting to 'win95'.\n",
130 return DRIVE_CASE_PRESERVING
;
134 /***********************************************************************
139 int i
, len
, count
= 0;
140 char name
[] = "Drive A";
141 char path
[MAX_PATHNAME_LEN
];
143 struct stat drive_stat_buffer
;
147 for (i
= 0, drive
= DOSDrives
; i
< MAX_DOS_DRIVES
; i
++, name
[6]++, drive
++)
149 PROFILE_GetWineIniString( name
, "Path", "", path
, sizeof(path
)-1 );
152 p
= path
+ strlen(path
) - 1;
153 while ((p
> path
) && ((*p
== '/') || (*p
== '\\'))) *p
-- = '\0';
154 if (!path
[0]) strcpy( path
, "/" );
156 if (stat( path
, &drive_stat_buffer
))
158 MESSAGE("Could not stat %s, ignoring drive %c:\n", path
, 'A' + i
);
161 if (!S_ISDIR(drive_stat_buffer
.st_mode
))
163 MESSAGE("%s is not a directory, ignoring drive %c:\n",
168 drive
->root
= HEAP_strdupA( SystemHeap
, 0, path
);
169 drive
->dos_cwd
= HEAP_strdupA( SystemHeap
, 0, "" );
170 drive
->unix_cwd
= HEAP_strdupA( SystemHeap
, 0, "" );
171 drive
->type
= DRIVE_GetDriveType( name
);
172 drive
->device
= NULL
;
174 drive
->dev
= drive_stat_buffer
.st_dev
;
175 drive
->ino
= drive_stat_buffer
.st_ino
;
177 /* Get the drive label */
178 PROFILE_GetWineIniString( name
, "Label", name
, drive
->label
, 12 );
179 if ((len
= strlen(drive
->label
)) < 11)
181 /* Pad label with spaces */
182 memset( drive
->label
+ len
, ' ', 11 - len
);
183 drive
->label
[12] = '\0';
186 /* Get the serial number */
187 PROFILE_GetWineIniString( name
, "Serial", "12345678",
188 buffer
, sizeof(buffer
) );
189 drive
->serial
= strtoul( buffer
, NULL
, 16 );
191 /* Get the filesystem type */
192 PROFILE_GetWineIniString( name
, "Filesystem", "win95",
193 buffer
, sizeof(buffer
) );
194 drive
->flags
= DRIVE_GetFSFlags( name
, buffer
);
197 PROFILE_GetWineIniString( name
, "Device", "",
198 buffer
, sizeof(buffer
) );
200 drive
->device
= HEAP_strdupA( SystemHeap
, 0, buffer
);
202 /* Make the first hard disk the current drive */
203 if ((DRIVE_CurDrive
== -1) && (drive
->type
== TYPE_HD
))
207 TRACE("%s: path=%s type=%s label='%s' serial=%08lx "
208 "flags=%08x dev=%x ino=%x\n",
209 name
, path
, DRIVE_Types
[drive
->type
],
210 drive
->label
, drive
->serial
, drive
->flags
,
211 (int)drive
->dev
, (int)drive
->ino
);
213 else WARN("%s: not defined\n", name
);
218 MESSAGE("Warning: no valid DOS drive found, check your configuration file.\n" );
219 /* Create a C drive pointing to Unix root dir */
220 DOSDrives
[2].root
= HEAP_strdupA( SystemHeap
, 0, "/" );
221 DOSDrives
[2].dos_cwd
= HEAP_strdupA( SystemHeap
, 0, "" );
222 DOSDrives
[2].unix_cwd
= HEAP_strdupA( SystemHeap
, 0, "" );
223 strcpy( DOSDrives
[2].label
, "Drive C " );
224 DOSDrives
[2].serial
= 0x12345678;
225 DOSDrives
[2].type
= TYPE_HD
;
226 DOSDrives
[2].flags
= 0;
230 /* Make sure the current drive is valid */
231 if (DRIVE_CurDrive
== -1)
233 for (i
= 0, drive
= DOSDrives
; i
< MAX_DOS_DRIVES
; i
++, drive
++)
235 if (drive
->root
&& !(drive
->flags
& DRIVE_DISABLED
))
247 /***********************************************************************
250 int DRIVE_IsValid( int drive
)
252 if ((drive
< 0) || (drive
>= MAX_DOS_DRIVES
)) return 0;
253 return (DOSDrives
[drive
].root
&&
254 !(DOSDrives
[drive
].flags
& DRIVE_DISABLED
));
258 /***********************************************************************
259 * DRIVE_GetCurrentDrive
261 int DRIVE_GetCurrentDrive(void)
263 TDB
*pTask
= (TDB
*)GlobalLock16( GetCurrentTask() );
264 if (pTask
&& (pTask
->curdrive
& 0x80)) return pTask
->curdrive
& ~0x80;
265 return DRIVE_CurDrive
;
269 /***********************************************************************
270 * DRIVE_SetCurrentDrive
272 int DRIVE_SetCurrentDrive( int drive
)
274 TDB
*pTask
= (TDB
*)GlobalLock16( GetCurrentTask() );
275 if (!DRIVE_IsValid( drive
))
277 SetLastError( ERROR_INVALID_DRIVE
);
280 TRACE("%c:\n", 'A' + drive
);
281 DRIVE_CurDrive
= drive
;
282 if (pTask
) pTask
->curdrive
= drive
| 0x80;
287 /***********************************************************************
288 * DRIVE_FindDriveRoot
290 * Find a drive for which the root matches the beginning of the given path.
291 * This can be used to translate a Unix path into a drive + DOS path.
292 * Return value is the drive, or -1 on error. On success, path is modified
293 * to point to the beginning of the DOS path.
295 int DRIVE_FindDriveRoot( const char **path
)
297 /* idea: check at all '/' positions.
298 * If the device and inode of that path is identical with the
299 * device and inode of the current drive then we found a solution.
300 * If there is another drive pointing to a deeper position in
301 * the file tree, we want to find that one, not the earlier solution.
303 int drive
, rootdrive
= -1;
304 char buffer
[MAX_PATHNAME_LEN
];
306 const char *p
= *path
;
309 strcpy( buffer
, "/" );
312 if (stat( buffer
, &st
) || !S_ISDIR( st
.st_mode
)) break;
316 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
318 if (!DOSDrives
[drive
].root
||
319 (DOSDrives
[drive
].flags
& DRIVE_DISABLED
)) continue;
321 if ((DOSDrives
[drive
].dev
== st
.st_dev
) &&
322 (DOSDrives
[drive
].ino
== st
.st_ino
))
329 /* Get the next path component */
332 while ((*p
== '/') || (*p
== '\\')) p
++;
334 while (!IS_END_OF_NAME(*p
)) *next
++ = *p
++;
340 TRACE("%s -> drive %c:, root='%s', name='%s'\n",
341 buffer
, 'A' + rootdrive
, DOSDrives
[rootdrive
].root
, *path
);
346 /***********************************************************************
349 const char * DRIVE_GetRoot( int drive
)
351 if (!DRIVE_IsValid( drive
)) return NULL
;
352 return DOSDrives
[drive
].root
;
356 /***********************************************************************
359 const char * DRIVE_GetDosCwd( int drive
)
361 TDB
*pTask
= (TDB
*)GlobalLock16( GetCurrentTask() );
362 if (!DRIVE_IsValid( drive
)) return NULL
;
364 /* Check if we need to change the directory to the new task. */
365 if (pTask
&& (pTask
->curdrive
& 0x80) && /* The task drive is valid */
366 ((pTask
->curdrive
& ~0x80) == drive
) && /* and it's the one we want */
367 (DRIVE_LastTask
!= GetCurrentTask())) /* and the task changed */
369 /* Perform the task-switch */
370 if (!DRIVE_Chdir( drive
, pTask
->curdir
)) DRIVE_Chdir( drive
, "\\" );
371 DRIVE_LastTask
= GetCurrentTask();
373 return DOSDrives
[drive
].dos_cwd
;
377 /***********************************************************************
380 const char * DRIVE_GetUnixCwd( int drive
)
382 TDB
*pTask
= (TDB
*)GlobalLock16( GetCurrentTask() );
383 if (!DRIVE_IsValid( drive
)) return NULL
;
385 /* Check if we need to change the directory to the new task. */
386 if (pTask
&& (pTask
->curdrive
& 0x80) && /* The task drive is valid */
387 ((pTask
->curdrive
& ~0x80) == drive
) && /* and it's the one we want */
388 (DRIVE_LastTask
!= GetCurrentTask())) /* and the task changed */
390 /* Perform the task-switch */
391 if (!DRIVE_Chdir( drive
, pTask
->curdir
)) DRIVE_Chdir( drive
, "\\" );
392 DRIVE_LastTask
= GetCurrentTask();
394 return DOSDrives
[drive
].unix_cwd
;
398 /***********************************************************************
401 const char * DRIVE_GetLabel( int drive
)
403 if (!DRIVE_IsValid( drive
)) return NULL
;
404 return DOSDrives
[drive
].label
;
408 /***********************************************************************
409 * DRIVE_GetSerialNumber
411 DWORD
DRIVE_GetSerialNumber( int drive
)
413 if (!DRIVE_IsValid( drive
)) return 0;
414 return DOSDrives
[drive
].serial
;
418 /***********************************************************************
419 * DRIVE_SetSerialNumber
421 int DRIVE_SetSerialNumber( int drive
, DWORD serial
)
423 if (!DRIVE_IsValid( drive
)) return 0;
424 DOSDrives
[drive
].serial
= serial
;
429 /***********************************************************************
432 DRIVETYPE
DRIVE_GetType( int drive
)
434 if (!DRIVE_IsValid( drive
)) return TYPE_INVALID
;
435 return DOSDrives
[drive
].type
;
439 /***********************************************************************
442 UINT
DRIVE_GetFlags( int drive
)
444 if ((drive
< 0) || (drive
>= MAX_DOS_DRIVES
)) return 0;
445 return DOSDrives
[drive
].flags
;
449 /***********************************************************************
452 int DRIVE_Chdir( int drive
, const char *path
)
454 DOS_FULL_NAME full_name
;
455 char buffer
[MAX_PATHNAME_LEN
];
457 BY_HANDLE_FILE_INFORMATION info
;
458 TDB
*pTask
= (TDB
*)GlobalLock16( GetCurrentTask() );
460 strcpy( buffer
, "A:" );
462 TRACE("(%c:,%s)\n", buffer
[0], path
);
463 lstrcpynA( buffer
+ 2, path
, sizeof(buffer
) - 2 );
465 if (!DOSFS_GetFullName( buffer
, TRUE
, &full_name
)) return 0;
466 if (!FILE_Stat( full_name
.long_name
, &info
)) return 0;
467 if (!(info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
))
469 SetLastError( ERROR_FILE_NOT_FOUND
);
472 unix_cwd
= full_name
.long_name
+ strlen( DOSDrives
[drive
].root
);
473 while (*unix_cwd
== '/') unix_cwd
++;
475 TRACE("(%c:): unix_cwd=%s dos_cwd=%s\n",
476 'A' + drive
, unix_cwd
, full_name
.short_name
+ 3 );
478 HeapFree( SystemHeap
, 0, DOSDrives
[drive
].dos_cwd
);
479 HeapFree( SystemHeap
, 0, DOSDrives
[drive
].unix_cwd
);
480 DOSDrives
[drive
].dos_cwd
= HEAP_strdupA( SystemHeap
, 0,
481 full_name
.short_name
+ 3 );
482 DOSDrives
[drive
].unix_cwd
= HEAP_strdupA( SystemHeap
, 0, unix_cwd
);
484 if (pTask
&& (pTask
->curdrive
& 0x80) &&
485 ((pTask
->curdrive
& ~0x80) == drive
))
487 lstrcpynA( pTask
->curdir
, full_name
.short_name
+ 2,
488 sizeof(pTask
->curdir
) );
489 DRIVE_LastTask
= GetCurrentTask();
495 /***********************************************************************
498 int DRIVE_Disable( int drive
)
500 if ((drive
< 0) || (drive
>= MAX_DOS_DRIVES
) || !DOSDrives
[drive
].root
)
502 SetLastError( ERROR_INVALID_DRIVE
);
505 DOSDrives
[drive
].flags
|= DRIVE_DISABLED
;
510 /***********************************************************************
513 int DRIVE_Enable( int drive
)
515 if ((drive
< 0) || (drive
>= MAX_DOS_DRIVES
) || !DOSDrives
[drive
].root
)
517 SetLastError( ERROR_INVALID_DRIVE
);
520 DOSDrives
[drive
].flags
&= ~DRIVE_DISABLED
;
525 /***********************************************************************
526 * DRIVE_SetLogicalMapping
528 int DRIVE_SetLogicalMapping ( int existing_drive
, int new_drive
)
530 /* If new_drive is already valid, do nothing and return 0
531 otherwise, copy DOSDrives[existing_drive] to DOSDrives[new_drive] */
535 old
= DOSDrives
+ existing_drive
;
536 new = DOSDrives
+ new_drive
;
538 if ((existing_drive
< 0) || (existing_drive
>= MAX_DOS_DRIVES
) ||
540 (new_drive
< 0) || (new_drive
>= MAX_DOS_DRIVES
))
542 SetLastError( ERROR_INVALID_DRIVE
);
548 TRACE("Can\'t map drive %c to drive %c - drive %c already exists\n",
549 'A' + existing_drive
, 'A' + new_drive
, 'A' + new_drive
);
550 /* it is already mapped there, so return success */
551 if (!strcmp(old
->root
,new->root
))
556 new->root
= HEAP_strdupA( SystemHeap
, 0, old
->root
);
557 new->dos_cwd
= HEAP_strdupA( SystemHeap
, 0, old
->dos_cwd
);
558 new->unix_cwd
= HEAP_strdupA( SystemHeap
, 0, old
->unix_cwd
);
559 memcpy ( new->label
, old
->label
, 12 );
560 new->serial
= old
->serial
;
561 new->type
= old
->type
;
562 new->flags
= old
->flags
;
566 TRACE("Drive %c is now equal to drive %c\n",
567 'A' + new_drive
, 'A' + existing_drive
);
573 /***********************************************************************
576 * Open the drive raw device and return a Unix fd (or -1 on error).
578 int DRIVE_OpenDevice( int drive
, int flags
)
580 if (!DRIVE_IsValid( drive
)) return -1;
581 return open( DOSDrives
[drive
].device
, flags
);
585 /***********************************************************************
588 * Read raw sectors from a device
590 int DRIVE_RawRead(BYTE drive
, DWORD begin
, DWORD nr_sect
, BYTE
*dataptr
, BOOL fake_success
)
594 if ((fd
= DRIVE_OpenDevice( drive
, O_RDONLY
)) != -1)
596 lseek( fd
, begin
* 512, SEEK_SET
);
597 /* FIXME: check errors */
598 read( fd
, dataptr
, nr_sect
* 512 );
603 memset(dataptr
, 0, nr_sect
* 512);
606 if (begin
== 0 && nr_sect
> 1) *(dataptr
+ 512) = 0xf8;
607 if (begin
== 1) *dataptr
= 0xf8;
616 /***********************************************************************
619 * Write raw sectors to a device
621 int DRIVE_RawWrite(BYTE drive
, DWORD begin
, DWORD nr_sect
, BYTE
*dataptr
, BOOL fake_success
)
625 if ((fd
= DRIVE_OpenDevice( drive
, O_RDONLY
)) != -1)
627 lseek( fd
, begin
* 512, SEEK_SET
);
628 /* FIXME: check errors */
629 write( fd
, dataptr
, nr_sect
* 512 );
640 /***********************************************************************
643 static int DRIVE_GetFreeSpace( int drive
, PULARGE_INTEGER size
,
644 PULARGE_INTEGER available
)
647 unsigned long long bigsize
,bigavail
=0;
649 if (!DRIVE_IsValid(drive
))
651 SetLastError( ERROR_INVALID_DRIVE
);
655 /* FIXME: add autoconf check for this */
656 #if defined(__svr4__) || defined(_SCO_DS) || defined(__sun)
657 if (statfs( DOSDrives
[drive
].root
, &info
, 0, 0) < 0)
659 if (statfs( DOSDrives
[drive
].root
, &info
) < 0)
663 WARN("cannot do statfs(%s)\n", DOSDrives
[drive
].root
);
667 bigsize
= (unsigned long long)info
.f_bsize
668 * (unsigned long long)info
.f_blocks
;
669 #ifdef STATFS_HAS_BAVAIL
670 bigavail
= (unsigned long long)info
.f_bavail
671 * (unsigned long long)info
.f_bsize
;
673 # ifdef STATFS_HAS_BFREE
674 bigavail
= (unsigned long long)info
.f_bfree
675 * (unsigned long long)info
.f_bsize
;
677 # error "statfs has no bfree/bavail member!"
680 size
->s
.LowPart
= (DWORD
)bigsize
;
681 size
->s
.HighPart
= (DWORD
)(bigsize
>>32);
682 available
->s
.LowPart
= (DWORD
)bigavail
;
683 available
->s
.HighPart
= (DWORD
)(bigavail
>>32);
687 /***********************************************************************
688 * DRIVE_GetCurrentDirectory
689 * Returns "X:\\path\\etc\\".
691 * Despite the API description, return required length including the
692 * terminating null when buffer too small. This is the real behaviour.
695 static UINT
DRIVE_GetCurrentDirectory( UINT buflen
, LPSTR buf
)
698 const char *s
= DRIVE_GetDosCwd( DRIVE_GetCurrentDrive() );
701 ret
= strlen(s
) + 3; /* length of WHOLE current directory */
702 if (ret
>= buflen
) return ret
+ 1;
703 lstrcpynA( buf
, "A:\\", MIN( 4, buflen
) );
704 if (buflen
) buf
[0] += DRIVE_GetCurrentDrive();
705 if (buflen
> 3) lstrcpynA( buf
+ 3, s
, buflen
- 3 );
709 /***********************************************************************
710 * GetDiskFreeSpace16 (KERNEL.422)
712 BOOL16 WINAPI
GetDiskFreeSpace16( LPCSTR root
, LPDWORD cluster_sectors
,
713 LPDWORD sector_bytes
, LPDWORD free_clusters
,
714 LPDWORD total_clusters
)
716 return GetDiskFreeSpaceA( root
, cluster_sectors
, sector_bytes
,
717 free_clusters
, total_clusters
);
721 /***********************************************************************
722 * GetDiskFreeSpace32A (KERNEL32.206)
724 * Fails if expression resulting from current drive's dir and "root"
725 * is not a root dir of the target drive.
727 * UNDOC: setting some LPDWORDs to NULL is perfectly possible
728 * if the corresponding info is unneeded.
730 * FIXME: needs to support UNC names from Win95 OSR2 on.
732 * Behaviour under Win95a:
733 * CurrDir root result
734 * "E:\\TEST" "E:" FALSE
738 * "E:\\TEST" "\\" TRUE
739 * "E:\\TEST" ":\\" FALSE
740 * "E:\\TEST" "E:\\" TRUE
741 * "E:\\TEST" "" FALSE
742 * "E:\\" "" FALSE (!)
744 * "E:\\TEST" 0x0 TRUE (!)
745 * "E:\\TEST" "C:" TRUE (when CurrDir of "C:" set to "\\")
746 * "E:\\TEST" "C:" FALSE (when CurrDir of "C:" set to "\\TEST")
748 BOOL WINAPI
GetDiskFreeSpaceA( LPCSTR root
, LPDWORD cluster_sectors
,
749 LPDWORD sector_bytes
, LPDWORD free_clusters
,
750 LPDWORD total_clusters
)
753 ULARGE_INTEGER size
,available
;
757 if ((!root
) || (strcmp(root
,"\\") == 0))
758 drive
= DRIVE_GetCurrentDrive();
760 if ( (strlen(root
) >= 2) && (root
[1] == ':')) /* root contains drive tag */
762 drive
= toupper(root
[0]) - 'A';
765 path
= DRIVE_GetDosCwd(drive
);
769 if (strlen(path
)) /* oops, we are in a subdir */
775 if (!DRIVE_GetFreeSpace(drive
, &size
, &available
)) return FALSE
;
777 /* Cap the size and available at 2GB as per specs. */
778 if ((size
.s
.HighPart
) ||(size
.s
.LowPart
> 0x7fffffff))
781 size
.s
.LowPart
= 0x7fffffff;
783 if ((available
.s
.HighPart
) ||(available
.s
.LowPart
> 0x7fffffff))
785 available
.s
.HighPart
=0;
786 available
.s
.LowPart
= 0x7fffffff;
788 if (DRIVE_GetType(drive
)==TYPE_CDROM
) {
790 *sector_bytes
= 2048;
791 size
.s
.LowPart
/= 2048;
792 available
.s
.LowPart
/= 2048;
796 size
.s
.LowPart
/= 512;
797 available
.s
.LowPart
/= 512;
799 /* fixme: probably have to adjust those variables too for CDFS */
801 while (cluster_sec
* 65536 < size
.s
.LowPart
) cluster_sec
*= 2;
804 *cluster_sectors
= cluster_sec
;
806 *free_clusters
= available
.s
.LowPart
/ cluster_sec
;
808 *total_clusters
= size
.s
.LowPart
/ cluster_sec
;
813 /***********************************************************************
814 * GetDiskFreeSpace32W (KERNEL32.207)
816 BOOL WINAPI
GetDiskFreeSpaceW( LPCWSTR root
, LPDWORD cluster_sectors
,
817 LPDWORD sector_bytes
, LPDWORD free_clusters
,
818 LPDWORD total_clusters
)
823 xroot
= HEAP_strdupWtoA( GetProcessHeap(), 0, root
);
824 ret
= GetDiskFreeSpaceA( xroot
,cluster_sectors
, sector_bytes
,
825 free_clusters
, total_clusters
);
826 HeapFree( GetProcessHeap(), 0, xroot
);
831 /***********************************************************************
832 * GetDiskFreeSpaceEx32A (KERNEL32.871)
834 * This function is used to aquire the size of the available and
835 * total space on a logical volume.
839 * Zero on failure, nonzero upon success. Use GetLastError to obtain
840 * detailed error information.
843 BOOL WINAPI
GetDiskFreeSpaceExA( LPCSTR root
,
844 PULARGE_INTEGER avail
,
845 PULARGE_INTEGER total
,
846 PULARGE_INTEGER totalfree
)
849 ULARGE_INTEGER size
,available
;
851 if (!root
) drive
= DRIVE_GetCurrentDrive();
854 if ((root
[1]) && ((root
[1] != ':') || (root
[2] != '\\')))
856 FIXME("there are valid root names which are not supported yet\n");
857 /* ..like UNC names, for instance. */
859 WARN("invalid root '%s'\n", root
);
862 drive
= toupper(root
[0]) - 'A';
865 if (!DRIVE_GetFreeSpace(drive
, &size
, &available
)) return FALSE
;
869 total
->s
.HighPart
= size
.s
.HighPart
;
870 total
->s
.LowPart
= size
.s
.LowPart
;
875 totalfree
->s
.HighPart
= available
.s
.HighPart
;
876 totalfree
->s
.LowPart
= available
.s
.LowPart
;
883 /* On Windows2000, we need to check the disk quota
884 allocated for the user owning the calling process. We
885 don't want to be more obtrusive than necessary with the
886 FIXME messages, so don't print the FIXME unless Wine is
887 actually masquerading as Windows2000. */
890 ovi
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOA
);
891 if (GetVersionExA(&ovi
))
893 if (ovi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
&& ovi
.dwMajorVersion
> 4)
894 FIXME("no per-user quota support yet\n");
898 /* Quick hack, should eventually be fixed to work 100% with
899 Windows2000 (see comment above). */
900 avail
->s
.HighPart
= available
.s
.HighPart
;
901 avail
->s
.LowPart
= available
.s
.LowPart
;
907 /***********************************************************************
908 * GetDiskFreeSpaceEx32W (KERNEL32.873)
910 BOOL WINAPI
GetDiskFreeSpaceExW( LPCWSTR root
, PULARGE_INTEGER avail
,
911 PULARGE_INTEGER total
,
912 PULARGE_INTEGER totalfree
)
917 xroot
= HEAP_strdupWtoA( GetProcessHeap(), 0, root
);
918 ret
= GetDiskFreeSpaceExA( xroot
, avail
, total
, totalfree
);
919 HeapFree( GetProcessHeap(), 0, xroot
);
923 /***********************************************************************
924 * GetDriveType16 (KERNEL.136)
925 * This functions returns the drivetype of a drive in Win16.
926 * Note that it returns DRIVE_REMOTE for CD-ROMs, since MSCDEX uses the
927 * remote drive API. The returnvalue DRIVE_REMOTE for CD-ROMs has been
928 * verified on Win3.11 and Windows 95. Some programs rely on it, so don't
929 * do any pseudo-clever changes.
932 * drivetype DRIVE_xxx
934 UINT16 WINAPI
GetDriveType16(
935 UINT16 drive
/* [in] number (NOT letter) of drive */
937 TRACE("(%c:)\n", 'A' + drive
);
938 switch(DRIVE_GetType(drive
))
940 case TYPE_FLOPPY
: return DRIVE_REMOVABLE
;
941 case TYPE_HD
: return DRIVE_FIXED
;
942 case TYPE_CDROM
: return DRIVE_REMOTE
;
943 case TYPE_NETWORK
: return DRIVE_REMOTE
;
945 default: return DRIVE_CANNOTDETERMINE
;
950 /***********************************************************************
951 * GetDriveType32A (KERNEL32.208)
953 * Returns the type of the disk drive specified. If root is NULL the
954 * root of the current directory is used.
958 * Type of drive (from Win32 SDK):
960 * DRIVE_UNKNOWN unable to find out anything about the drive
961 * DRIVE_NO_ROOT_DIR nonexistand root dir
962 * DRIVE_REMOVABLE the disk can be removed from the machine
963 * DRIVE_FIXED the disk can not be removed from the machine
964 * DRIVE_REMOTE network disk
965 * DRIVE_CDROM CDROM drive
966 * DRIVE_RAMDISK virtual disk in ram
968 * DRIVE_DOESNOTEXIST XXX Not valid return value
969 * DRIVE_CANNOTDETERMINE XXX Not valid return value
973 * Currently returns DRIVE_DOESNOTEXIST and DRIVE_CANNOTDETERMINE
974 * when it really should return DRIVE_NO_ROOT_DIR and DRIVE_UNKNOWN.
975 * Why where the former defines used?
977 * DRIVE_RAMDISK is unsupported.
979 UINT WINAPI
GetDriveTypeA(LPCSTR root
/* String describing drive */)
982 TRACE("(%s)\n", debugstr_a(root
));
984 if (NULL
== root
) drive
= DRIVE_GetCurrentDrive();
987 if ((root
[1]) && (root
[1] != ':'))
989 WARN("invalid root '%s'\n", debugstr_a(root
));
990 return DRIVE_DOESNOTEXIST
;
992 drive
= toupper(root
[0]) - 'A';
994 switch(DRIVE_GetType(drive
))
996 case TYPE_FLOPPY
: return DRIVE_REMOVABLE
;
997 case TYPE_HD
: return DRIVE_FIXED
;
998 case TYPE_CDROM
: return DRIVE_CDROM
;
999 case TYPE_NETWORK
: return DRIVE_REMOTE
;
1000 case TYPE_INVALID
: return DRIVE_DOESNOTEXIST
;
1001 default: return DRIVE_CANNOTDETERMINE
;
1006 /***********************************************************************
1007 * GetDriveType32W (KERNEL32.209)
1009 UINT WINAPI
GetDriveTypeW( LPCWSTR root
)
1011 LPSTR xpath
= HEAP_strdupWtoA( GetProcessHeap(), 0, root
);
1012 UINT ret
= GetDriveTypeA( xpath
);
1013 HeapFree( GetProcessHeap(), 0, xpath
);
1018 /***********************************************************************
1019 * GetCurrentDirectory16 (KERNEL.411)
1021 UINT16 WINAPI
GetCurrentDirectory16( UINT16 buflen
, LPSTR buf
)
1023 return (UINT16
)DRIVE_GetCurrentDirectory(buflen
, buf
);
1027 /***********************************************************************
1028 * GetCurrentDirectory32A (KERNEL32.196)
1030 UINT WINAPI
GetCurrentDirectoryA( UINT buflen
, LPSTR buf
)
1033 char longname
[MAX_PATHNAME_LEN
];
1034 char shortname
[MAX_PATHNAME_LEN
];
1035 ret
= DRIVE_GetCurrentDirectory(MAX_PATHNAME_LEN
, shortname
);
1036 if ( ret
> MAX_PATHNAME_LEN
) {
1037 ERR_(file
)("pathnamelength (%d) > MAX_PATHNAME_LEN!\n", ret
);
1040 GetLongPathNameA(shortname
, longname
, MAX_PATHNAME_LEN
);
1041 ret
= lstrlenA( longname
) + 1;
1042 if (ret
> buflen
) return ret
;
1043 lstrcpyA(buf
, longname
);
1047 /***********************************************************************
1048 * GetCurrentDirectory32W (KERNEL32.197)
1050 UINT WINAPI
GetCurrentDirectoryW( UINT buflen
, LPWSTR buf
)
1052 LPSTR xpath
= HeapAlloc( GetProcessHeap(), 0, buflen
+1 );
1053 UINT ret
= GetCurrentDirectoryA( buflen
, xpath
);
1054 if (ret
< buflen
) lstrcpyAtoW ( buf
, xpath
);
1055 HeapFree( GetProcessHeap(), 0, xpath
);
1060 /***********************************************************************
1061 * SetCurrentDirectory (KERNEL.412)
1063 BOOL16 WINAPI
SetCurrentDirectory16( LPCSTR dir
)
1065 return SetCurrentDirectoryA( dir
);
1069 /***********************************************************************
1070 * SetCurrentDirectory32A (KERNEL32.479)
1072 BOOL WINAPI
SetCurrentDirectoryA( LPCSTR dir
)
1074 int olddrive
, drive
= DRIVE_GetCurrentDrive();
1077 ERR_(file
)("(NULL)!\n");
1080 if (dir
[0] && (dir
[1]==':'))
1082 drive
= tolower( *dir
) - 'a';
1086 /* WARNING: we need to set the drive before the dir, as DRIVE_Chdir
1087 sets pTask->curdir only if pTask->curdrive is drive */
1088 olddrive
= drive
; /* in case DRIVE_Chdir fails */
1089 if (!(DRIVE_SetCurrentDrive( drive
)))
1091 /* FIXME: what about empty strings? Add a \\ ? */
1092 if (!DRIVE_Chdir( drive
, dir
)) {
1093 DRIVE_SetCurrentDrive(olddrive
);
1100 /***********************************************************************
1101 * SetCurrentDirectory32W (KERNEL32.480)
1103 BOOL WINAPI
SetCurrentDirectoryW( LPCWSTR dirW
)
1105 LPSTR dir
= HEAP_strdupWtoA( GetProcessHeap(), 0, dirW
);
1106 BOOL res
= SetCurrentDirectoryA( dir
);
1107 HeapFree( GetProcessHeap(), 0, dir
);
1112 /***********************************************************************
1113 * GetLogicalDriveStrings32A (KERNEL32.231)
1115 UINT WINAPI
GetLogicalDriveStringsA( UINT len
, LPSTR buffer
)
1119 for (drive
= count
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
1120 if (DRIVE_IsValid(drive
)) count
++;
1121 if ((count
* 4) + 1 <= len
)
1124 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
1125 if (DRIVE_IsValid(drive
))
1136 return (count
* 4) + 1;/* account for terminating null */
1137 /* The API tells about these different return values */
1141 /***********************************************************************
1142 * GetLogicalDriveStrings32W (KERNEL32.232)
1144 UINT WINAPI
GetLogicalDriveStringsW( UINT len
, LPWSTR buffer
)
1148 for (drive
= count
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
1149 if (DRIVE_IsValid(drive
)) count
++;
1150 if (count
* 4 * sizeof(WCHAR
) <= len
)
1153 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
1154 if (DRIVE_IsValid(drive
))
1156 *p
++ = (WCHAR
)('a' + drive
);
1163 return count
* 4 * sizeof(WCHAR
);
1167 /***********************************************************************
1168 * GetLogicalDrives (KERNEL32.233)
1170 DWORD WINAPI
GetLogicalDrives(void)
1175 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
1176 if (DRIVE_IsValid(drive
)) ret
|= (1 << drive
);
1181 /***********************************************************************
1182 * GetVolumeInformation32A (KERNEL32.309)
1184 BOOL WINAPI
GetVolumeInformationA( LPCSTR root
, LPSTR label
,
1185 DWORD label_len
, DWORD
*serial
,
1186 DWORD
*filename_len
, DWORD
*flags
,
1187 LPSTR fsname
, DWORD fsname_len
)
1192 /* FIXME, SetLastErrors missing */
1194 if (!root
) drive
= DRIVE_GetCurrentDrive();
1197 if ((root
[1]) && (root
[1] != ':'))
1199 WARN("invalid root '%s'\n",root
);
1202 drive
= toupper(root
[0]) - 'A';
1204 if (!DRIVE_IsValid( drive
)) return FALSE
;
1207 lstrcpynA( label
, DRIVE_GetLabel(drive
), label_len
);
1208 for (cp
= label
; *cp
; cp
++);
1209 while (cp
!= label
&& *(cp
-1) == ' ') cp
--;
1212 if (serial
) *serial
= DRIVE_GetSerialNumber(drive
);
1214 /* Set the filesystem information */
1215 /* Note: we only emulate a FAT fs at the present */
1218 if (DOSDrives
[drive
].flags
& DRIVE_SHORT_NAMES
)
1221 *filename_len
= 255;
1226 if (DOSDrives
[drive
].flags
& DRIVE_CASE_SENSITIVE
)
1227 *flags
|=FS_CASE_SENSITIVE
;
1228 if (DOSDrives
[drive
].flags
& DRIVE_CASE_PRESERVING
)
1229 *flags
|=FS_CASE_IS_PRESERVED
;
1232 /* Diablo checks that return code ... */
1233 if (DRIVE_GetType(drive
)==TYPE_CDROM
)
1234 lstrcpynA( fsname
, "CDFS", fsname_len
);
1236 lstrcpynA( fsname
, "FAT", fsname_len
);
1242 /***********************************************************************
1243 * GetVolumeInformation32W (KERNEL32.310)
1245 BOOL WINAPI
GetVolumeInformationW( LPCWSTR root
, LPWSTR label
,
1246 DWORD label_len
, DWORD
*serial
,
1247 DWORD
*filename_len
, DWORD
*flags
,
1248 LPWSTR fsname
, DWORD fsname_len
)
1250 LPSTR xroot
= HEAP_strdupWtoA( GetProcessHeap(), 0, root
);
1251 LPSTR xvolname
= label
? HeapAlloc(GetProcessHeap(),0,label_len
) : NULL
;
1252 LPSTR xfsname
= fsname
? HeapAlloc(GetProcessHeap(),0,fsname_len
) : NULL
;
1253 BOOL ret
= GetVolumeInformationA( xroot
, xvolname
, label_len
, serial
,
1254 filename_len
, flags
, xfsname
,
1258 if (label
) lstrcpyAtoW( label
, xvolname
);
1259 if (fsname
) lstrcpyAtoW( fsname
, xfsname
);
1261 HeapFree( GetProcessHeap(), 0, xroot
);
1262 HeapFree( GetProcessHeap(), 0, xvolname
);
1263 HeapFree( GetProcessHeap(), 0, xfsname
);
1267 /***********************************************************************
1268 * SetVolumeLabelA (KERNEL32.675)
1270 BOOL WINAPI
SetVolumeLabelA(LPCSTR rootpath
,LPCSTR volname
)
1272 FIXME("(%s,%s),stub!\n",rootpath
,volname
);
1276 /***********************************************************************
1277 * SetVolumeLabelW (KERNEL32.676)
1279 BOOL WINAPI
SetVolumeLabelW(LPCWSTR rootpath
,LPCWSTR volname
)
1284 xroot
= HEAP_strdupWtoA( GetProcessHeap(), 0, rootpath
);
1285 xvol
= HEAP_strdupWtoA( GetProcessHeap(), 0, volname
);
1286 ret
= SetVolumeLabelA( xroot
, xvol
);
1287 HeapFree( GetProcessHeap(), 0, xroot
);
1288 HeapFree( GetProcessHeap(), 0, xvol
);