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 DECLARE_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_(dosfs
)("%s: path=%s type=%s label='%s' serial=%08lx flags=%08x dev=%x ino=%x\n",
208 name
, path
, DRIVE_Types
[drive
->type
],
209 drive
->label
, drive
->serial
, drive
->flags
,
210 (int)drive
->dev
, (int)drive
->ino
);
212 else WARN_(dosfs
)("%s: not defined\n", name
);
217 MESSAGE("Warning: no valid DOS drive found, check your configuration file.\n" );
218 /* Create a C drive pointing to Unix root dir */
219 DOSDrives
[2].root
= HEAP_strdupA( SystemHeap
, 0, "/" );
220 DOSDrives
[2].dos_cwd
= HEAP_strdupA( SystemHeap
, 0, "" );
221 DOSDrives
[2].unix_cwd
= HEAP_strdupA( SystemHeap
, 0, "" );
222 strcpy( DOSDrives
[2].label
, "Drive C " );
223 DOSDrives
[2].serial
= 0x12345678;
224 DOSDrives
[2].type
= TYPE_HD
;
225 DOSDrives
[2].flags
= 0;
229 /* Make sure the current drive is valid */
230 if (DRIVE_CurDrive
== -1)
232 for (i
= 0, drive
= DOSDrives
; i
< MAX_DOS_DRIVES
; i
++, drive
++)
234 if (drive
->root
&& !(drive
->flags
& DRIVE_DISABLED
))
246 /***********************************************************************
249 int DRIVE_IsValid( int drive
)
251 if ((drive
< 0) || (drive
>= MAX_DOS_DRIVES
)) return 0;
252 return (DOSDrives
[drive
].root
&&
253 !(DOSDrives
[drive
].flags
& DRIVE_DISABLED
));
257 /***********************************************************************
258 * DRIVE_GetCurrentDrive
260 int DRIVE_GetCurrentDrive(void)
262 TDB
*pTask
= (TDB
*)GlobalLock16( GetCurrentTask() );
263 if (pTask
&& (pTask
->curdrive
& 0x80)) return pTask
->curdrive
& ~0x80;
264 return DRIVE_CurDrive
;
268 /***********************************************************************
269 * DRIVE_SetCurrentDrive
271 int DRIVE_SetCurrentDrive( int drive
)
273 TDB
*pTask
= (TDB
*)GlobalLock16( GetCurrentTask() );
274 if (!DRIVE_IsValid( drive
))
276 SetLastError( ERROR_INVALID_DRIVE
);
279 TRACE_(dosfs
)("%c:\n", 'A' + drive
);
280 DRIVE_CurDrive
= drive
;
281 if (pTask
) pTask
->curdrive
= drive
| 0x80;
286 /***********************************************************************
287 * DRIVE_FindDriveRoot
289 * Find a drive for which the root matches the beginning of the given path.
290 * This can be used to translate a Unix path into a drive + DOS path.
291 * Return value is the drive, or -1 on error. On success, path is modified
292 * to point to the beginning of the DOS path.
294 int DRIVE_FindDriveRoot( const char **path
)
296 /* idea: check at all '/' positions.
297 * If the device and inode of that path is identical with the
298 * device and inode of the current drive then we found a solution.
299 * If there is another drive pointing to a deeper position in
300 * the file tree, we want to find that one, not the earlier solution.
302 int drive
, rootdrive
= -1;
303 char buffer
[MAX_PATHNAME_LEN
];
305 const char *p
= *path
;
308 strcpy( buffer
, "/" );
311 if (stat( buffer
, &st
) || !S_ISDIR( st
.st_mode
)) break;
315 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
317 if (!DOSDrives
[drive
].root
||
318 (DOSDrives
[drive
].flags
& DRIVE_DISABLED
)) continue;
320 if ((DOSDrives
[drive
].dev
== st
.st_dev
) &&
321 (DOSDrives
[drive
].ino
== st
.st_ino
))
328 /* Get the next path component */
331 while ((*p
== '/') || (*p
== '\\')) p
++;
333 while (!IS_END_OF_NAME(*p
)) *next
++ = *p
++;
339 TRACE_(dosfs
)("%s -> drive %c:, root='%s', name='%s'\n",
340 buffer
, 'A' + rootdrive
,
341 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_(dosfs
)("(%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_(dosfs
)("(%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_(dosfs
)("Can\'t map drive %c to drive %c - "
549 "drive %c already exists\n",
550 'A' + existing_drive
, 'A' + new_drive
,
552 /* it is already mapped there, so return success */
553 if (!strcmp(old
->root
,new->root
))
558 new->root
= HEAP_strdupA( SystemHeap
, 0, old
->root
);
559 new->dos_cwd
= HEAP_strdupA( SystemHeap
, 0, old
->dos_cwd
);
560 new->unix_cwd
= HEAP_strdupA( SystemHeap
, 0, old
->unix_cwd
);
561 memcpy ( new->label
, old
->label
, 12 );
562 new->serial
= old
->serial
;
563 new->type
= old
->type
;
564 new->flags
= old
->flags
;
568 TRACE_(dosfs
)("Drive %c is now equal to drive %c\n",
569 'A' + new_drive
, 'A' + existing_drive
);
575 /***********************************************************************
578 * Open the drive raw device and return a Unix fd (or -1 on error).
580 int DRIVE_OpenDevice( int drive
, int flags
)
582 if (!DRIVE_IsValid( drive
)) return -1;
583 return open( DOSDrives
[drive
].device
, flags
);
587 /***********************************************************************
590 * Read raw sectors from a device
592 int DRIVE_RawRead(BYTE drive
, DWORD begin
, DWORD nr_sect
, BYTE
*dataptr
, BOOL fake_success
)
596 if ((fd
= DRIVE_OpenDevice( drive
, O_RDONLY
)) != -1)
598 lseek( fd
, begin
* 512, SEEK_SET
);
599 /* FIXME: check errors */
600 read( fd
, dataptr
, nr_sect
* 512 );
605 memset(dataptr
, 0, nr_sect
* 512);
608 if (begin
== 0 && nr_sect
> 1) *(dataptr
+ 512) = 0xf8;
609 if (begin
== 1) *dataptr
= 0xf8;
618 /***********************************************************************
621 * Write raw sectors to a device
623 int DRIVE_RawWrite(BYTE drive
, DWORD begin
, DWORD nr_sect
, BYTE
*dataptr
, BOOL fake_success
)
627 if ((fd
= DRIVE_OpenDevice( drive
, O_RDONLY
)) != -1)
629 lseek( fd
, begin
* 512, SEEK_SET
);
630 /* FIXME: check errors */
631 write( fd
, dataptr
, nr_sect
* 512 );
642 /***********************************************************************
645 static int DRIVE_GetFreeSpace( int drive
, PULARGE_INTEGER size
,
646 PULARGE_INTEGER available
)
649 unsigned long long bigsize
,bigavail
=0;
651 if (!DRIVE_IsValid(drive
))
653 SetLastError( ERROR_INVALID_DRIVE
);
657 /* FIXME: add autoconf check for this */
658 #if defined(__svr4__) || defined(_SCO_DS) || defined(__sun)
659 if (statfs( DOSDrives
[drive
].root
, &info
, 0, 0) < 0)
661 if (statfs( DOSDrives
[drive
].root
, &info
) < 0)
665 WARN_(dosfs
)("cannot do statfs(%s)\n", DOSDrives
[drive
].root
);
669 bigsize
= (unsigned long long)info
.f_bsize
670 * (unsigned long long)info
.f_blocks
;
671 #ifdef STATFS_HAS_BAVAIL
672 bigavail
= (unsigned long long)info
.f_bavail
673 * (unsigned long long)info
.f_bsize
;
675 # ifdef STATFS_HAS_BFREE
676 bigavail
= (unsigned long long)info
.f_bfree
677 * (unsigned long long)info
.f_bsize
;
679 # error "statfs has no bfree/bavail member!"
682 size
->s
.LowPart
= (DWORD
)bigsize
;
683 size
->s
.HighPart
= (DWORD
)(bigsize
>>32);
684 available
->s
.LowPart
= (DWORD
)bigavail
;
685 available
->s
.HighPart
= (DWORD
)(bigavail
>>32);
689 /***********************************************************************
690 * DRIVE_GetCurrentDirectory
691 * Returns "X:\\path\\etc\\".
693 * Despite the API description, return required length including the
694 * terminating null when buffer too small. This is the real behaviour.
697 static UINT
DRIVE_GetCurrentDirectory( UINT buflen
, LPSTR buf
)
700 const char *s
= DRIVE_GetDosCwd( DRIVE_GetCurrentDrive() );
703 ret
= strlen(s
) + 3; /* length of WHOLE current directory */
704 if (ret
>= buflen
) return ret
+ 1;
705 lstrcpynA( buf
, "A:\\", MIN( 4, buflen
) );
706 if (buflen
) buf
[0] += DRIVE_GetCurrentDrive();
707 if (buflen
> 3) lstrcpynA( buf
+ 3, s
, buflen
- 3 );
711 /***********************************************************************
712 * GetDiskFreeSpace16 (KERNEL.422)
714 BOOL16 WINAPI
GetDiskFreeSpace16( LPCSTR root
, LPDWORD cluster_sectors
,
715 LPDWORD sector_bytes
, LPDWORD free_clusters
,
716 LPDWORD total_clusters
)
718 return GetDiskFreeSpaceA( root
, cluster_sectors
, sector_bytes
,
719 free_clusters
, total_clusters
);
723 /***********************************************************************
724 * GetDiskFreeSpace32A (KERNEL32.206)
726 * Fails if expression resulting from current drive's dir and "root"
727 * is not a root dir of the target drive.
729 * UNDOC: setting some LPDWORDs to NULL is perfectly possible
730 * if the corresponding info is unneeded.
732 * FIXME: needs to support UNC names from Win95 OSR2 on.
734 * Behaviour under Win95a:
735 * CurrDir root result
736 * "E:\\TEST" "E:" FALSE
740 * "E:\\TEST" "\\" TRUE
741 * "E:\\TEST" ":\\" FALSE
742 * "E:\\TEST" "E:\\" TRUE
743 * "E:\\TEST" "" FALSE
744 * "E:\\" "" FALSE (!)
746 * "E:\\TEST" 0x0 TRUE (!)
747 * "E:\\TEST" "C:" TRUE (when CurrDir of "C:" set to "\\")
748 * "E:\\TEST" "C:" FALSE (when CurrDir of "C:" set to "\\TEST")
750 BOOL WINAPI
GetDiskFreeSpaceA( LPCSTR root
, LPDWORD cluster_sectors
,
751 LPDWORD sector_bytes
, LPDWORD free_clusters
,
752 LPDWORD total_clusters
)
755 ULARGE_INTEGER size
,available
;
759 if ((!root
) || (strcmp(root
,"\\") == 0))
760 drive
= DRIVE_GetCurrentDrive();
762 if ( (strlen(root
) >= 2) && (root
[1] == ':')) /* root contains drive tag */
764 drive
= toupper(root
[0]) - 'A';
767 path
= DRIVE_GetDosCwd(drive
);
771 if (strlen(path
)) /* oops, we are in a subdir */
777 if (!DRIVE_GetFreeSpace(drive
, &size
, &available
)) return FALSE
;
779 /* Cap the size and available at 2GB as per specs. */
780 if ((size
.s
.HighPart
) ||(size
.s
.LowPart
> 0x7fffffff))
783 size
.s
.LowPart
= 0x7fffffff;
785 if ((available
.s
.HighPart
) ||(available
.s
.LowPart
> 0x7fffffff))
787 available
.s
.HighPart
=0;
788 available
.s
.LowPart
= 0x7fffffff;
790 if (DRIVE_GetType(drive
)==TYPE_CDROM
) {
792 *sector_bytes
= 2048;
793 size
.s
.LowPart
/= 2048;
794 available
.s
.LowPart
/= 2048;
798 size
.s
.LowPart
/= 512;
799 available
.s
.LowPart
/= 512;
801 /* fixme: probably have to adjust those variables too for CDFS */
803 while (cluster_sec
* 65536 < size
.s
.LowPart
) cluster_sec
*= 2;
806 *cluster_sectors
= cluster_sec
;
808 *free_clusters
= available
.s
.LowPart
/ cluster_sec
;
810 *total_clusters
= size
.s
.LowPart
/ cluster_sec
;
815 /***********************************************************************
816 * GetDiskFreeSpace32W (KERNEL32.207)
818 BOOL WINAPI
GetDiskFreeSpaceW( LPCWSTR root
, LPDWORD cluster_sectors
,
819 LPDWORD sector_bytes
, LPDWORD free_clusters
,
820 LPDWORD total_clusters
)
825 xroot
= HEAP_strdupWtoA( GetProcessHeap(), 0, root
);
826 ret
= GetDiskFreeSpaceA( xroot
,cluster_sectors
, sector_bytes
,
827 free_clusters
, total_clusters
);
828 HeapFree( GetProcessHeap(), 0, xroot
);
833 /***********************************************************************
834 * GetDiskFreeSpaceEx32A (KERNEL32.871)
836 * This function is used to aquire the size of the available and
837 * total space on a logical volume.
841 * Zero on failure, nonzero upon success. Use GetLastError to obtain
842 * detailed error information.
845 BOOL WINAPI
GetDiskFreeSpaceExA( LPCSTR root
,
846 PULARGE_INTEGER avail
,
847 PULARGE_INTEGER total
,
848 PULARGE_INTEGER totalfree
)
851 ULARGE_INTEGER size
,available
;
853 if (!root
) drive
= DRIVE_GetCurrentDrive();
856 if ((root
[1]) && ((root
[1] != ':') || (root
[2] != '\\')))
858 FIXME_(dosfs
)("there are valid root names which are not supported yet\n");
859 /* ..like UNC names, for instance. */
861 WARN_(dosfs
)("invalid root '%s'\n", root
);
864 drive
= toupper(root
[0]) - 'A';
867 if (!DRIVE_GetFreeSpace(drive
, &size
, &available
)) return FALSE
;
871 total
->s
.HighPart
= size
.s
.HighPart
;
872 total
->s
.LowPart
= size
.s
.LowPart
;
877 totalfree
->s
.HighPart
= available
.s
.HighPart
;
878 totalfree
->s
.LowPart
= available
.s
.LowPart
;
885 /* On Windows2000, we need to check the disk quota
886 allocated for the user owning the calling process. We
887 don't want to be more obtrusive than necessary with the
888 FIXME messages, so don't print the FIXME unless Wine is
889 actually masquerading as Windows2000. */
892 ovi
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOA
);
893 if (GetVersionExA(&ovi
))
895 if (ovi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
&& ovi
.dwMajorVersion
> 4)
896 FIXME_(dosfs
)("no per-user quota support yet\n");
900 /* Quick hack, should eventually be fixed to work 100% with
901 Windows2000 (see comment above). */
902 avail
->s
.HighPart
= available
.s
.HighPart
;
903 avail
->s
.LowPart
= available
.s
.LowPart
;
909 /***********************************************************************
910 * GetDiskFreeSpaceEx32W (KERNEL32.873)
912 BOOL WINAPI
GetDiskFreeSpaceExW( LPCWSTR root
, PULARGE_INTEGER avail
,
913 PULARGE_INTEGER total
,
914 PULARGE_INTEGER totalfree
)
919 xroot
= HEAP_strdupWtoA( GetProcessHeap(), 0, root
);
920 ret
= GetDiskFreeSpaceExA( xroot
, avail
, total
, totalfree
);
921 HeapFree( GetProcessHeap(), 0, xroot
);
925 /***********************************************************************
926 * GetDriveType16 (KERNEL.136)
927 * This functions returns the drivetype of a drive in Win16.
928 * Note that it returns DRIVE_REMOTE for CD-ROMs, since MSCDEX uses the
929 * remote drive API. The returnvalue DRIVE_REMOTE for CD-ROMs has been
930 * verified on Win3.11 and Windows 95. Some programs rely on it, so don't
931 * do any pseudo-clever changes.
934 * drivetype DRIVE_xxx
936 UINT16 WINAPI
GetDriveType16(
937 UINT16 drive
/* [in] number (NOT letter) of drive */
939 TRACE_(dosfs
)("(%c:)\n", 'A' + drive
);
940 switch(DRIVE_GetType(drive
))
942 case TYPE_FLOPPY
: return DRIVE_REMOVABLE
;
943 case TYPE_HD
: return DRIVE_FIXED
;
944 case TYPE_CDROM
: return DRIVE_REMOTE
;
945 case TYPE_NETWORK
: return DRIVE_REMOTE
;
947 default: return DRIVE_CANNOTDETERMINE
;
952 /***********************************************************************
953 * GetDriveType32A (KERNEL32.208)
955 * Returns the type of the disk drive specified. If root is NULL the
956 * root of the current directory is used.
960 * Type of drive (from Win32 SDK):
962 * DRIVE_UNKNOWN unable to find out anything about the drive
963 * DRIVE_NO_ROOT_DIR nonexistand root dir
964 * DRIVE_REMOVABLE the disk can be removed from the machine
965 * DRIVE_FIXED the disk can not be removed from the machine
966 * DRIVE_REMOTE network disk
967 * DRIVE_CDROM CDROM drive
968 * DRIVE_RAMDISK virtual disk in ram
970 * DRIVE_DOESNOTEXIST XXX Not valid return value
971 * DRIVE_CANNOTDETERMINE XXX Not valid return value
975 * Currently returns DRIVE_DOESNOTEXIST and DRIVE_CANNOTDETERMINE
976 * when it really should return DRIVE_NO_ROOT_DIR and DRIVE_UNKNOWN.
977 * Why where the former defines used?
979 * DRIVE_RAMDISK is unsupported.
981 UINT WINAPI
GetDriveTypeA(LPCSTR root
/* String describing drive */)
984 TRACE_(dosfs
)("(%s)\n", debugstr_a(root
));
986 if (NULL
== root
) drive
= DRIVE_GetCurrentDrive();
989 if ((root
[1]) && (root
[1] != ':'))
991 WARN_(dosfs
)("invalid root '%s'\n", debugstr_a(root
));
992 return DRIVE_DOESNOTEXIST
;
994 drive
= toupper(root
[0]) - 'A';
996 switch(DRIVE_GetType(drive
))
998 case TYPE_FLOPPY
: return DRIVE_REMOVABLE
;
999 case TYPE_HD
: return DRIVE_FIXED
;
1000 case TYPE_CDROM
: return DRIVE_CDROM
;
1001 case TYPE_NETWORK
: return DRIVE_REMOTE
;
1002 case TYPE_INVALID
: return DRIVE_DOESNOTEXIST
;
1003 default: return DRIVE_CANNOTDETERMINE
;
1008 /***********************************************************************
1009 * GetDriveType32W (KERNEL32.209)
1011 UINT WINAPI
GetDriveTypeW( LPCWSTR root
)
1013 LPSTR xpath
= HEAP_strdupWtoA( GetProcessHeap(), 0, root
);
1014 UINT ret
= GetDriveTypeA( xpath
);
1015 HeapFree( GetProcessHeap(), 0, xpath
);
1020 /***********************************************************************
1021 * GetCurrentDirectory16 (KERNEL.411)
1023 UINT16 WINAPI
GetCurrentDirectory16( UINT16 buflen
, LPSTR buf
)
1025 return (UINT16
)DRIVE_GetCurrentDirectory(buflen
, buf
);
1029 /***********************************************************************
1030 * GetCurrentDirectory32A (KERNEL32.196)
1032 UINT WINAPI
GetCurrentDirectoryA( UINT buflen
, LPSTR buf
)
1035 char longname
[MAX_PATHNAME_LEN
];
1036 char shortname
[MAX_PATHNAME_LEN
];
1037 ret
= DRIVE_GetCurrentDirectory(MAX_PATHNAME_LEN
, shortname
);
1038 if ( ret
> MAX_PATHNAME_LEN
) {
1039 ERR_(file
)("pathnamelength (%d) > MAX_PATHNAME_LEN!\n", ret
);
1042 GetLongPathNameA(shortname
, longname
, MAX_PATHNAME_LEN
);
1043 ret
= lstrlenA( longname
) + 1;
1044 if (ret
> buflen
) return ret
;
1045 lstrcpyA(buf
, longname
);
1049 /***********************************************************************
1050 * GetCurrentDirectory32W (KERNEL32.197)
1052 UINT WINAPI
GetCurrentDirectoryW( UINT buflen
, LPWSTR buf
)
1054 LPSTR xpath
= HeapAlloc( GetProcessHeap(), 0, buflen
+1 );
1055 UINT ret
= GetCurrentDirectoryA( buflen
, xpath
);
1056 if (ret
< buflen
) lstrcpyAtoW ( buf
, xpath
);
1057 HeapFree( GetProcessHeap(), 0, xpath
);
1062 /***********************************************************************
1063 * SetCurrentDirectory (KERNEL.412)
1065 BOOL16 WINAPI
SetCurrentDirectory16( LPCSTR dir
)
1067 return SetCurrentDirectoryA( dir
);
1071 /***********************************************************************
1072 * SetCurrentDirectory32A (KERNEL32.479)
1074 BOOL WINAPI
SetCurrentDirectoryA( LPCSTR dir
)
1076 int olddrive
, drive
= DRIVE_GetCurrentDrive();
1079 ERR_(file
)("(NULL)!\n");
1082 if (dir
[0] && (dir
[1]==':'))
1084 drive
= tolower( *dir
) - 'a';
1088 /* WARNING: we need to set the drive before the dir, as DRIVE_Chdir
1089 sets pTask->curdir only if pTask->curdrive is drive */
1090 olddrive
= drive
; /* in case DRIVE_Chdir fails */
1091 if (!(DRIVE_SetCurrentDrive( drive
)))
1093 /* FIXME: what about empty strings? Add a \\ ? */
1094 if (!DRIVE_Chdir( drive
, dir
)) {
1095 DRIVE_SetCurrentDrive(olddrive
);
1102 /***********************************************************************
1103 * SetCurrentDirectory32W (KERNEL32.480)
1105 BOOL WINAPI
SetCurrentDirectoryW( LPCWSTR dirW
)
1107 LPSTR dir
= HEAP_strdupWtoA( GetProcessHeap(), 0, dirW
);
1108 BOOL res
= SetCurrentDirectoryA( dir
);
1109 HeapFree( GetProcessHeap(), 0, dir
);
1114 /***********************************************************************
1115 * GetLogicalDriveStrings32A (KERNEL32.231)
1117 UINT WINAPI
GetLogicalDriveStringsA( UINT len
, LPSTR buffer
)
1121 for (drive
= count
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
1122 if (DRIVE_IsValid(drive
)) count
++;
1123 if ((count
* 4) + 1 <= len
)
1126 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
1127 if (DRIVE_IsValid(drive
))
1138 return (count
* 4) + 1;/* account for terminating null */
1139 /* The API tells about these different return values */
1143 /***********************************************************************
1144 * GetLogicalDriveStrings32W (KERNEL32.232)
1146 UINT WINAPI
GetLogicalDriveStringsW( UINT len
, LPWSTR buffer
)
1150 for (drive
= count
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
1151 if (DRIVE_IsValid(drive
)) count
++;
1152 if (count
* 4 * sizeof(WCHAR
) <= len
)
1155 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
1156 if (DRIVE_IsValid(drive
))
1158 *p
++ = (WCHAR
)('a' + drive
);
1165 return count
* 4 * sizeof(WCHAR
);
1169 /***********************************************************************
1170 * GetLogicalDrives (KERNEL32.233)
1172 DWORD WINAPI
GetLogicalDrives(void)
1177 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
1178 if (DRIVE_IsValid(drive
)) ret
|= (1 << drive
);
1183 /***********************************************************************
1184 * GetVolumeInformation32A (KERNEL32.309)
1186 BOOL WINAPI
GetVolumeInformationA( LPCSTR root
, LPSTR label
,
1187 DWORD label_len
, DWORD
*serial
,
1188 DWORD
*filename_len
, DWORD
*flags
,
1189 LPSTR fsname
, DWORD fsname_len
)
1194 /* FIXME, SetLastErrors missing */
1196 if (!root
) drive
= DRIVE_GetCurrentDrive();
1199 if ((root
[1]) && (root
[1] != ':'))
1201 WARN_(dosfs
)("invalid root '%s'\n",root
);
1204 drive
= toupper(root
[0]) - 'A';
1206 if (!DRIVE_IsValid( drive
)) return FALSE
;
1209 lstrcpynA( label
, DRIVE_GetLabel(drive
), label_len
);
1210 for (cp
= label
; *cp
; cp
++);
1211 while (cp
!= label
&& *(cp
-1) == ' ') cp
--;
1214 if (serial
) *serial
= DRIVE_GetSerialNumber(drive
);
1216 /* Set the filesystem information */
1217 /* Note: we only emulate a FAT fs at the present */
1220 if (DOSDrives
[drive
].flags
& DRIVE_SHORT_NAMES
)
1223 *filename_len
= 255;
1228 if (DOSDrives
[drive
].flags
& DRIVE_CASE_SENSITIVE
)
1229 *flags
|=FS_CASE_SENSITIVE
;
1230 if (DOSDrives
[drive
].flags
& DRIVE_CASE_PRESERVING
)
1231 *flags
|=FS_CASE_IS_PRESERVED
;
1234 /* Diablo checks that return code ... */
1235 if (DRIVE_GetType(drive
)==TYPE_CDROM
)
1236 lstrcpynA( fsname
, "CDFS", fsname_len
);
1238 lstrcpynA( fsname
, "FAT", fsname_len
);
1244 /***********************************************************************
1245 * GetVolumeInformation32W (KERNEL32.310)
1247 BOOL WINAPI
GetVolumeInformationW( LPCWSTR root
, LPWSTR label
,
1248 DWORD label_len
, DWORD
*serial
,
1249 DWORD
*filename_len
, DWORD
*flags
,
1250 LPWSTR fsname
, DWORD fsname_len
)
1252 LPSTR xroot
= HEAP_strdupWtoA( GetProcessHeap(), 0, root
);
1253 LPSTR xvolname
= label
? HeapAlloc(GetProcessHeap(),0,label_len
) : NULL
;
1254 LPSTR xfsname
= fsname
? HeapAlloc(GetProcessHeap(),0,fsname_len
) : NULL
;
1255 BOOL ret
= GetVolumeInformationA( xroot
, xvolname
, label_len
, serial
,
1256 filename_len
, flags
, xfsname
,
1260 if (label
) lstrcpyAtoW( label
, xvolname
);
1261 if (fsname
) lstrcpyAtoW( fsname
, xfsname
);
1263 HeapFree( GetProcessHeap(), 0, xroot
);
1264 HeapFree( GetProcessHeap(), 0, xvolname
);
1265 HeapFree( GetProcessHeap(), 0, xfsname
);
1269 /***********************************************************************
1270 * SetVolumeLabelA (KERNEL32.675)
1272 BOOL WINAPI
SetVolumeLabelA(LPCSTR rootpath
,LPCSTR volname
)
1274 FIXME_(dosfs
)("(%s,%s),stub!\n",rootpath
,volname
);
1278 /***********************************************************************
1279 * SetVolumeLabelW (KERNEL32.676)
1281 BOOL WINAPI
SetVolumeLabelW(LPCWSTR rootpath
,LPCWSTR volname
)
1286 xroot
= HEAP_strdupWtoA( GetProcessHeap(), 0, rootpath
);
1287 xvol
= HEAP_strdupWtoA( GetProcessHeap(), 0, volname
);
1288 ret
= SetVolumeLabelA( xroot
, xvol
);
1289 HeapFree( GetProcessHeap(), 0, xroot
);
1290 HeapFree( GetProcessHeap(), 0, xvol
);