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 */
47 DECLARE_DEBUG_CHANNEL(dosfs
)
48 DECLARE_DEBUG_CHANNEL(file
)
52 char *root
; /* root dir in Unix format without trailing / */
53 char *dos_cwd
; /* cwd in DOS format without leading or trailing \ */
54 char *unix_cwd
; /* cwd in Unix format without leading or trailing / */
55 char *device
; /* raw device path */
56 char label
[12]; /* drive label */
57 DWORD serial
; /* drive serial number */
58 DRIVETYPE type
; /* drive type */
59 UINT flags
; /* drive flags */
60 dev_t dev
; /* unix device number */
61 ino_t ino
; /* unix inode number */
65 static const char * const DRIVE_Types
[] =
67 "floppy", /* TYPE_FLOPPY */
69 "cdrom", /* TYPE_CDROM */
70 "network" /* TYPE_NETWORK */
74 /* Known filesystem types */
82 static const FS_DESCR DRIVE_Filesystems
[] =
84 { "unix", DRIVE_CASE_SENSITIVE
| DRIVE_CASE_PRESERVING
},
85 { "msdos", DRIVE_SHORT_NAMES
},
86 { "dos", DRIVE_SHORT_NAMES
},
87 { "fat", DRIVE_SHORT_NAMES
},
88 { "vfat", DRIVE_CASE_PRESERVING
},
89 { "win95", DRIVE_CASE_PRESERVING
},
94 static DOSDRIVE DOSDrives
[MAX_DOS_DRIVES
];
95 static int DRIVE_CurDrive
= -1;
97 static HTASK16 DRIVE_LastTask
= 0;
100 /***********************************************************************
103 static DRIVETYPE
DRIVE_GetDriveType( const char *name
)
108 PROFILE_GetWineIniString( name
, "Type", "hd", buffer
, sizeof(buffer
) );
109 for (i
= 0; i
< sizeof(DRIVE_Types
)/sizeof(DRIVE_Types
[0]); i
++)
111 if (!strcasecmp( buffer
, DRIVE_Types
[i
] )) return (DRIVETYPE
)i
;
113 MSG("%s: unknown type '%s', defaulting to 'hd'.\n", name
, buffer
);
118 /***********************************************************************
121 static UINT
DRIVE_GetFSFlags( const char *name
, const char *value
)
123 const FS_DESCR
*descr
;
125 for (descr
= DRIVE_Filesystems
; descr
->name
; descr
++)
126 if (!strcasecmp( value
, descr
->name
)) return descr
->flags
;
127 MSG("%s: unknown filesystem type '%s', defaulting to 'win95'.\n",
129 return DRIVE_CASE_PRESERVING
;
133 /***********************************************************************
138 int i
, len
, count
= 0;
139 char name
[] = "Drive A";
140 char path
[MAX_PATHNAME_LEN
];
142 struct stat drive_stat_buffer
;
146 for (i
= 0, drive
= DOSDrives
; i
< MAX_DOS_DRIVES
; i
++, name
[6]++, drive
++)
148 PROFILE_GetWineIniString( name
, "Path", "", path
, sizeof(path
)-1 );
151 p
= path
+ strlen(path
) - 1;
152 while ((p
> path
) && ((*p
== '/') || (*p
== '\\'))) *p
-- = '\0';
153 if (!path
[0]) strcpy( path
, "/" );
155 if (stat( path
, &drive_stat_buffer
))
157 MSG("Could not stat %s, ignoring drive %c:\n", path
, 'A' + i
);
160 if (!S_ISDIR(drive_stat_buffer
.st_mode
))
162 MSG("%s is not a directory, ignoring drive %c:\n",
167 drive
->root
= HEAP_strdupA( SystemHeap
, 0, path
);
168 drive
->dos_cwd
= HEAP_strdupA( SystemHeap
, 0, "" );
169 drive
->unix_cwd
= HEAP_strdupA( SystemHeap
, 0, "" );
170 drive
->type
= DRIVE_GetDriveType( name
);
171 drive
->device
= NULL
;
173 drive
->dev
= drive_stat_buffer
.st_dev
;
174 drive
->ino
= drive_stat_buffer
.st_ino
;
176 /* Get the drive label */
177 PROFILE_GetWineIniString( name
, "Label", name
, drive
->label
, 12 );
178 if ((len
= strlen(drive
->label
)) < 11)
180 /* Pad label with spaces */
181 memset( drive
->label
+ len
, ' ', 11 - len
);
182 drive
->label
[12] = '\0';
185 /* Get the serial number */
186 PROFILE_GetWineIniString( name
, "Serial", "12345678",
187 buffer
, sizeof(buffer
) );
188 drive
->serial
= strtoul( buffer
, NULL
, 16 );
190 /* Get the filesystem type */
191 PROFILE_GetWineIniString( name
, "Filesystem", "win95",
192 buffer
, sizeof(buffer
) );
193 drive
->flags
= DRIVE_GetFSFlags( name
, buffer
);
196 PROFILE_GetWineIniString( name
, "Device", "",
197 buffer
, sizeof(buffer
) );
199 drive
->device
= HEAP_strdupA( SystemHeap
, 0, buffer
);
201 /* Make the first hard disk the current drive */
202 if ((DRIVE_CurDrive
== -1) && (drive
->type
== TYPE_HD
))
206 TRACE(dosfs
, "%s: path=%s type=%s label='%s' serial=%08lx flags=%08x dev=%x ino=%x\n",
207 name
, path
, DRIVE_Types
[drive
->type
],
208 drive
->label
, drive
->serial
, drive
->flags
,
209 (int)drive
->dev
, (int)drive
->ino
);
211 else WARN(dosfs
, "%s: not defined\n", name
);
216 MSG("Warning: no valid DOS drive found, check your configuration file.\n" );
217 /* Create a C drive pointing to Unix root dir */
218 DOSDrives
[2].root
= HEAP_strdupA( SystemHeap
, 0, "/" );
219 DOSDrives
[2].dos_cwd
= HEAP_strdupA( SystemHeap
, 0, "" );
220 DOSDrives
[2].unix_cwd
= HEAP_strdupA( SystemHeap
, 0, "" );
221 strcpy( DOSDrives
[2].label
, "Drive C " );
222 DOSDrives
[2].serial
= 0x12345678;
223 DOSDrives
[2].type
= TYPE_HD
;
224 DOSDrives
[2].flags
= 0;
228 /* Make sure the current drive is valid */
229 if (DRIVE_CurDrive
== -1)
231 for (i
= 0, drive
= DOSDrives
; i
< MAX_DOS_DRIVES
; i
++, drive
++)
233 if (drive
->root
&& !(drive
->flags
& DRIVE_DISABLED
))
245 /***********************************************************************
248 int DRIVE_IsValid( int drive
)
250 if ((drive
< 0) || (drive
>= MAX_DOS_DRIVES
)) return 0;
251 return (DOSDrives
[drive
].root
&&
252 !(DOSDrives
[drive
].flags
& DRIVE_DISABLED
));
256 /***********************************************************************
257 * DRIVE_GetCurrentDrive
259 int DRIVE_GetCurrentDrive(void)
261 TDB
*pTask
= (TDB
*)GlobalLock16( GetCurrentTask() );
262 if (pTask
&& (pTask
->curdrive
& 0x80)) return pTask
->curdrive
& ~0x80;
263 return DRIVE_CurDrive
;
267 /***********************************************************************
268 * DRIVE_SetCurrentDrive
270 int DRIVE_SetCurrentDrive( int drive
)
272 TDB
*pTask
= (TDB
*)GlobalLock16( GetCurrentTask() );
273 if (!DRIVE_IsValid( drive
))
275 SetLastError( ERROR_INVALID_DRIVE
);
278 TRACE(dosfs
, "%c:\n", 'A' + drive
);
279 DRIVE_CurDrive
= drive
;
280 if (pTask
) pTask
->curdrive
= drive
| 0x80;
285 /***********************************************************************
286 * DRIVE_FindDriveRoot
288 * Find a drive for which the root matches the begginning of the given path.
289 * This can be used to translate a Unix path into a drive + DOS path.
290 * Return value is the drive, or -1 on error. On success, path is modified
291 * to point to the beginning of the DOS path.
293 int DRIVE_FindDriveRoot( const char **path
)
295 /* idea: check at all '/' positions.
296 * If the device and inode of that path is identical with the
297 * device and inode of the current drive then we found a solution.
298 * If there is another drive pointing to a deeper position in
299 * the file tree, we want to find that one, not the earlier solution.
301 int drive
, rootdrive
= -1;
302 char buffer
[MAX_PATHNAME_LEN
];
304 const char *p
= *path
;
307 strcpy( buffer
, "/" );
310 if (stat( buffer
, &st
) || !S_ISDIR( st
.st_mode
)) break;
314 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
316 if (!DOSDrives
[drive
].root
||
317 (DOSDrives
[drive
].flags
& DRIVE_DISABLED
)) continue;
319 if ((DOSDrives
[drive
].dev
== st
.st_dev
) &&
320 (DOSDrives
[drive
].ino
== st
.st_ino
))
327 /* Get the next path component */
330 while ((*p
== '/') || (*p
== '\\')) p
++;
332 while (!IS_END_OF_NAME(*p
)) *next
++ = *p
++;
338 TRACE(dosfs
, "%s -> drive %c:, root='%s', name='%s'\n",
339 buffer
, 'A' + rootdrive
,
340 DOSDrives
[rootdrive
].root
, *path
);
345 /***********************************************************************
348 const char * DRIVE_GetRoot( int drive
)
350 if (!DRIVE_IsValid( drive
)) return NULL
;
351 return DOSDrives
[drive
].root
;
355 /***********************************************************************
358 const char * DRIVE_GetDosCwd( int drive
)
360 TDB
*pTask
= (TDB
*)GlobalLock16( GetCurrentTask() );
361 if (!DRIVE_IsValid( drive
)) return NULL
;
363 /* Check if we need to change the directory to the new task. */
364 if (pTask
&& (pTask
->curdrive
& 0x80) && /* The task drive is valid */
365 ((pTask
->curdrive
& ~0x80) == drive
) && /* and it's the one we want */
366 (DRIVE_LastTask
!= GetCurrentTask())) /* and the task changed */
368 /* Perform the task-switch */
369 if (!DRIVE_Chdir( drive
, pTask
->curdir
)) DRIVE_Chdir( drive
, "\\" );
370 DRIVE_LastTask
= GetCurrentTask();
372 return DOSDrives
[drive
].dos_cwd
;
376 /***********************************************************************
379 const char * DRIVE_GetUnixCwd( int drive
)
381 TDB
*pTask
= (TDB
*)GlobalLock16( GetCurrentTask() );
382 if (!DRIVE_IsValid( drive
)) return NULL
;
384 /* Check if we need to change the directory to the new task. */
385 if (pTask
&& (pTask
->curdrive
& 0x80) && /* The task drive is valid */
386 ((pTask
->curdrive
& ~0x80) == drive
) && /* and it's the one we want */
387 (DRIVE_LastTask
!= GetCurrentTask())) /* and the task changed */
389 /* Perform the task-switch */
390 if (!DRIVE_Chdir( drive
, pTask
->curdir
)) DRIVE_Chdir( drive
, "\\" );
391 DRIVE_LastTask
= GetCurrentTask();
393 return DOSDrives
[drive
].unix_cwd
;
397 /***********************************************************************
400 const char * DRIVE_GetLabel( int drive
)
402 if (!DRIVE_IsValid( drive
)) return NULL
;
403 return DOSDrives
[drive
].label
;
407 /***********************************************************************
408 * DRIVE_GetSerialNumber
410 DWORD
DRIVE_GetSerialNumber( int drive
)
412 if (!DRIVE_IsValid( drive
)) return 0;
413 return DOSDrives
[drive
].serial
;
417 /***********************************************************************
418 * DRIVE_SetSerialNumber
420 int DRIVE_SetSerialNumber( int drive
, DWORD serial
)
422 if (!DRIVE_IsValid( drive
)) return 0;
423 DOSDrives
[drive
].serial
= serial
;
428 /***********************************************************************
431 DRIVETYPE
DRIVE_GetType( int drive
)
433 if (!DRIVE_IsValid( drive
)) return TYPE_INVALID
;
434 return DOSDrives
[drive
].type
;
438 /***********************************************************************
441 UINT
DRIVE_GetFlags( int drive
)
443 if ((drive
< 0) || (drive
>= MAX_DOS_DRIVES
)) return 0;
444 return DOSDrives
[drive
].flags
;
448 /***********************************************************************
451 int DRIVE_Chdir( int drive
, const char *path
)
453 DOS_FULL_NAME full_name
;
454 char buffer
[MAX_PATHNAME_LEN
];
456 BY_HANDLE_FILE_INFORMATION info
;
457 TDB
*pTask
= (TDB
*)GlobalLock16( GetCurrentTask() );
459 strcpy( buffer
, "A:" );
461 TRACE(dosfs
, "(%c:,%s)\n", buffer
[0], path
);
462 lstrcpynA( buffer
+ 2, path
, sizeof(buffer
) - 2 );
464 if (!DOSFS_GetFullName( buffer
, TRUE
, &full_name
)) return 0;
465 if (!FILE_Stat( full_name
.long_name
, &info
)) return 0;
466 if (!(info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
))
468 SetLastError( ERROR_FILE_NOT_FOUND
);
471 unix_cwd
= full_name
.long_name
+ strlen( DOSDrives
[drive
].root
);
472 while (*unix_cwd
== '/') unix_cwd
++;
474 TRACE(dosfs
, "(%c:): unix_cwd=%s dos_cwd=%s\n",
475 'A' + drive
, unix_cwd
, full_name
.short_name
+ 3 );
477 HeapFree( SystemHeap
, 0, DOSDrives
[drive
].dos_cwd
);
478 HeapFree( SystemHeap
, 0, DOSDrives
[drive
].unix_cwd
);
479 DOSDrives
[drive
].dos_cwd
= HEAP_strdupA( SystemHeap
, 0,
480 full_name
.short_name
+ 3 );
481 DOSDrives
[drive
].unix_cwd
= HEAP_strdupA( SystemHeap
, 0, unix_cwd
);
483 if (pTask
&& (pTask
->curdrive
& 0x80) &&
484 ((pTask
->curdrive
& ~0x80) == drive
))
486 lstrcpynA( pTask
->curdir
, full_name
.short_name
+ 2,
487 sizeof(pTask
->curdir
) );
488 DRIVE_LastTask
= GetCurrentTask();
494 /***********************************************************************
497 int DRIVE_Disable( int drive
)
499 if ((drive
< 0) || (drive
>= MAX_DOS_DRIVES
) || !DOSDrives
[drive
].root
)
501 SetLastError( ERROR_INVALID_DRIVE
);
504 DOSDrives
[drive
].flags
|= DRIVE_DISABLED
;
509 /***********************************************************************
512 int DRIVE_Enable( int drive
)
514 if ((drive
< 0) || (drive
>= MAX_DOS_DRIVES
) || !DOSDrives
[drive
].root
)
516 SetLastError( ERROR_INVALID_DRIVE
);
519 DOSDrives
[drive
].flags
&= ~DRIVE_DISABLED
;
524 /***********************************************************************
525 * DRIVE_SetLogicalMapping
527 int DRIVE_SetLogicalMapping ( int existing_drive
, int new_drive
)
529 /* If new_drive is already valid, do nothing and return 0
530 otherwise, copy DOSDrives[existing_drive] to DOSDrives[new_drive] */
534 old
= DOSDrives
+ existing_drive
;
535 new = DOSDrives
+ new_drive
;
537 if ((existing_drive
< 0) || (existing_drive
>= MAX_DOS_DRIVES
) ||
539 (new_drive
< 0) || (new_drive
>= MAX_DOS_DRIVES
))
541 SetLastError( ERROR_INVALID_DRIVE
);
547 TRACE(dosfs
, "Can\'t map drive %c to drive %c - "
548 "drive %c already exists\n",
549 'A' + existing_drive
, 'A' + new_drive
,
551 /* it is already mapped there, so return success */
552 if (!strcmp(old
->root
,new->root
))
557 new->root
= HEAP_strdupA( SystemHeap
, 0, old
->root
);
558 new->dos_cwd
= HEAP_strdupA( SystemHeap
, 0, old
->dos_cwd
);
559 new->unix_cwd
= HEAP_strdupA( SystemHeap
, 0, old
->unix_cwd
);
560 memcpy ( new->label
, old
->label
, 12 );
561 new->serial
= old
->serial
;
562 new->type
= old
->type
;
563 new->flags
= old
->flags
;
567 TRACE(dosfs
, "Drive %c is now equal to drive %c\n",
568 'A' + new_drive
, 'A' + existing_drive
);
574 /***********************************************************************
577 * Open the drive raw device and return a Unix fd (or -1 on error).
579 int DRIVE_OpenDevice( int drive
, int flags
)
581 if (!DRIVE_IsValid( drive
)) return -1;
582 return open( DOSDrives
[drive
].device
, flags
);
586 /***********************************************************************
589 * Read raw sectors from a device
591 int DRIVE_RawRead(BYTE drive
, DWORD begin
, DWORD nr_sect
, BYTE
*dataptr
, BOOL fake_success
)
595 if ((fd
= DRIVE_OpenDevice( drive
, O_RDONLY
)) != -1)
597 lseek( fd
, begin
* 512, SEEK_SET
);
598 /* FIXME: check errors */
599 read( fd
, dataptr
, nr_sect
* 512 );
604 memset(dataptr
, 0, nr_sect
* 512);
607 if (begin
== 0 && nr_sect
> 1) *(dataptr
+ 512) = 0xf8;
608 if (begin
== 1) *dataptr
= 0xf8;
617 /***********************************************************************
620 * Write raw sectors to a device
622 int DRIVE_RawWrite(BYTE drive
, DWORD begin
, DWORD nr_sect
, BYTE
*dataptr
, BOOL fake_success
)
626 if ((fd
= DRIVE_OpenDevice( drive
, O_RDONLY
)) != -1)
628 lseek( fd
, begin
* 512, SEEK_SET
);
629 /* FIXME: check errors */
630 write( fd
, dataptr
, nr_sect
* 512 );
641 /***********************************************************************
644 static int DRIVE_GetFreeSpace( int drive
, PULARGE_INTEGER size
,
645 PULARGE_INTEGER available
)
648 unsigned long long bigsize
,bigavail
=0;
650 if (!DRIVE_IsValid(drive
))
652 SetLastError( ERROR_INVALID_DRIVE
);
656 /* FIXME: add autoconf check for this */
657 #if defined(__svr4__) || defined(_SCO_DS) || defined(__sun)
658 if (statfs( DOSDrives
[drive
].root
, &info
, 0, 0) < 0)
660 if (statfs( DOSDrives
[drive
].root
, &info
) < 0)
664 WARN(dosfs
, "cannot do statfs(%s)\n", DOSDrives
[drive
].root
);
668 bigsize
= (unsigned long long)info
.f_bsize
669 * (unsigned long long)info
.f_blocks
;
670 #ifdef STATFS_HAS_BAVAIL
671 bigavail
= (unsigned long long)info
.f_bavail
672 * (unsigned long long)info
.f_bsize
;
674 # ifdef STATFS_HAS_BFREE
675 bigavail
= (unsigned long long)info
.f_bfree
676 * (unsigned long long)info
.f_bsize
;
678 # error "statfs has no bfree/bavail member!"
681 size
->LowPart
= (DWORD
)bigsize
;
682 size
->HighPart
= (DWORD
)(bigsize
>>32);
683 available
->LowPart
= (DWORD
)bigavail
;
684 available
->HighPart
= (DWORD
)(bigavail
>>32);
689 /***********************************************************************
690 * GetDiskFreeSpace16 (KERNEL.422)
692 BOOL16 WINAPI
GetDiskFreeSpace16( LPCSTR root
, LPDWORD cluster_sectors
,
693 LPDWORD sector_bytes
, LPDWORD free_clusters
,
694 LPDWORD total_clusters
)
696 return GetDiskFreeSpaceA( root
, cluster_sectors
, sector_bytes
,
697 free_clusters
, total_clusters
);
701 /***********************************************************************
702 * GetDiskFreeSpace32A (KERNEL32.206)
704 * Fails if expression resulting from current drive's dir and "root"
705 * is not a root dir of the target drive.
707 * UNDOC: setting some LPDWORDs to NULL is perfectly possible
708 * if the corresponding info is unneeded.
710 * FIXME: needs to support UNC names from Win95 OSR2 on.
712 * Behaviour under Win95a:
713 * CurrDir root result
714 * "E:\\TEST" "E:" FALSE
718 * "E:\\TEST" "\\" TRUE
719 * "E:\\TEST" ":\\" FALSE
720 * "E:\\TEST" "E:\\" TRUE
721 * "E:\\TEST" "" FALSE
722 * "E:\\" "" FALSE (!)
724 * "E:\\TEST" 0x0 TRUE (!)
725 * "E:\\TEST" "C:" TRUE (when CurrDir of "C:" set to "\\")
726 * "E:\\TEST" "C:" FALSE (when CurrDir of "C:" set to "\\TEST")
728 BOOL WINAPI
GetDiskFreeSpaceA( LPCSTR root
, LPDWORD cluster_sectors
,
729 LPDWORD sector_bytes
, LPDWORD free_clusters
,
730 LPDWORD total_clusters
)
733 ULARGE_INTEGER size
,available
;
737 if ((!root
) || (root
== "\\"))
738 drive
= DRIVE_GetCurrentDrive();
740 if ( (strlen(root
) >= 2) && (root
[1] == ':')) /* root contains drive tag */
742 drive
= toupper(root
[0]) - 'A';
745 path
= DRIVE_GetDosCwd(drive
);
749 if (strlen(path
)) /* oops, we are in a subdir */
755 if (!DRIVE_GetFreeSpace(drive
, &size
, &available
)) return FALSE
;
757 /* Cap the size and available at 2GB as per specs. */
758 if ((size
.HighPart
) ||(size
.LowPart
> 0x7fffffff))
761 size
.LowPart
= 0x7fffffff;
763 if ((available
.HighPart
) ||(available
.LowPart
> 0x7fffffff))
765 available
.HighPart
=0;
766 available
.LowPart
= 0x7fffffff;
768 if (DRIVE_GetType(drive
)==TYPE_CDROM
) {
770 *sector_bytes
= 2048;
771 size
.LowPart
/= 2048;
772 available
.LowPart
/= 2048;
777 available
.LowPart
/= 512;
779 /* fixme: probably have to adjust those variables too for CDFS */
781 while (cluster_sec
* 65536 < size
.LowPart
) cluster_sec
*= 2;
784 *cluster_sectors
= cluster_sec
;
786 *free_clusters
= available
.LowPart
/ cluster_sec
;
788 *total_clusters
= size
.LowPart
/ cluster_sec
;
793 /***********************************************************************
794 * GetDiskFreeSpace32W (KERNEL32.207)
796 BOOL WINAPI
GetDiskFreeSpaceW( LPCWSTR root
, LPDWORD cluster_sectors
,
797 LPDWORD sector_bytes
, LPDWORD free_clusters
,
798 LPDWORD total_clusters
)
803 xroot
= HEAP_strdupWtoA( GetProcessHeap(), 0, root
);
804 ret
= GetDiskFreeSpaceA( xroot
,cluster_sectors
, sector_bytes
,
805 free_clusters
, total_clusters
);
806 HeapFree( GetProcessHeap(), 0, xroot
);
811 /***********************************************************************
812 * GetDiskFreeSpaceEx32A (KERNEL32.871)
814 BOOL WINAPI
GetDiskFreeSpaceExA( LPCSTR root
,
815 PULARGE_INTEGER avail
,
816 PULARGE_INTEGER total
,
817 PULARGE_INTEGER totalfree
)
820 ULARGE_INTEGER size
,available
;
822 if (!root
) drive
= DRIVE_GetCurrentDrive();
825 if ((root
[1]) && ((root
[1] != ':') || (root
[2] != '\\')))
827 WARN(dosfs
, "invalid root '%s'\n", root
);
830 drive
= toupper(root
[0]) - 'A';
832 if (!DRIVE_GetFreeSpace(drive
, &size
, &available
)) return FALSE
;
833 /*FIXME: Do we have the number of bytes available to the user? */
835 totalfree
->HighPart
= size
.HighPart
;
836 totalfree
->LowPart
= size
.LowPart
;
839 avail
->HighPart
= available
.HighPart
;
840 avail
->LowPart
= available
.LowPart
;
845 /***********************************************************************
846 * GetDiskFreeSpaceEx32W (KERNEL32.873)
848 BOOL WINAPI
GetDiskFreeSpaceExW( LPCWSTR root
, PULARGE_INTEGER avail
,
849 PULARGE_INTEGER total
,
850 PULARGE_INTEGER totalfree
)
855 xroot
= HEAP_strdupWtoA( GetProcessHeap(), 0, root
);
856 ret
= GetDiskFreeSpaceExA( xroot
, avail
, total
, totalfree
);
857 HeapFree( GetProcessHeap(), 0, xroot
);
861 /***********************************************************************
862 * GetDriveType16 (KERNEL.136)
863 * This functions returns the drivetype of a drive in Win16.
864 * Note that it returns DRIVE_REMOTE for CD-ROMs, since MSCDEX uses the
865 * remote drive API. The returnvalue DRIVE_REMOTE for CD-ROMs has been
866 * verified on Win3.11 and Windows 95. Some programs rely on it, so don't
867 * do any pseudo-clever changes.
870 * drivetype DRIVE_xxx
872 UINT16 WINAPI
GetDriveType16(
873 UINT16 drive
/* [in] number (NOT letter) of drive */
875 TRACE(dosfs
, "(%c:)\n", 'A' + drive
);
876 switch(DRIVE_GetType(drive
))
878 case TYPE_FLOPPY
: return DRIVE_REMOVABLE
;
879 case TYPE_HD
: return DRIVE_FIXED
;
880 case TYPE_CDROM
: return DRIVE_REMOTE
;
881 case TYPE_NETWORK
: return DRIVE_REMOTE
;
883 default: return DRIVE_CANNOTDETERMINE
;
888 /***********************************************************************
889 * GetDriveType32A (KERNEL32.208)
891 * Returns the type of the disk drive specified. If root is NULL the
892 * root of the current directory is used.
896 * Type of drive (from Win32 SDK):
898 * DRIVE_UNKNOWN unable to find out anything about the drive
899 * DRIVE_NO_ROOT_DIR nonexistand root dir
900 * DRIVE_REMOVABLE the disk can be removed from the machine
901 * DRIVE_FIXED the disk can not be removed from the machine
902 * DRIVE_REMOTE network disk
903 * DRIVE_CDROM CDROM drive
904 * DRIVE_RAMDISK virtual disk in ram
906 * DRIVE_DOESNOTEXIST XXX Not valid return value
907 * DRIVE_CANNOTDETERMINE XXX Not valid return value
911 * Currently returns DRIVE_DOESNOTEXIST and DRIVE_CANNOTDETERMINE
912 * when it really should return DRIVE_NO_ROOT_DIR and DRIVE_UNKNOWN.
913 * Why where the former defines used?
915 * DRIVE_RAMDISK is unsupported.
917 UINT WINAPI
GetDriveTypeA(LPCSTR root
/* String describing drive */)
920 TRACE(dosfs
, "(%s)\n", debugstr_a(root
));
922 if (NULL
== root
) drive
= DRIVE_GetCurrentDrive();
925 if ((root
[1]) && (root
[1] != ':'))
927 WARN(dosfs
, "invalid root '%s'\n", debugstr_a(root
));
928 return DRIVE_DOESNOTEXIST
;
930 drive
= toupper(root
[0]) - 'A';
932 switch(DRIVE_GetType(drive
))
934 case TYPE_FLOPPY
: return DRIVE_REMOVABLE
;
935 case TYPE_HD
: return DRIVE_FIXED
;
936 case TYPE_CDROM
: return DRIVE_CDROM
;
937 case TYPE_NETWORK
: return DRIVE_REMOTE
;
938 case TYPE_INVALID
: return DRIVE_DOESNOTEXIST
;
939 default: return DRIVE_CANNOTDETERMINE
;
944 /***********************************************************************
945 * GetDriveType32W (KERNEL32.209)
947 UINT WINAPI
GetDriveTypeW( LPCWSTR root
)
949 LPSTR xpath
= HEAP_strdupWtoA( GetProcessHeap(), 0, root
);
950 UINT ret
= GetDriveTypeA( xpath
);
951 HeapFree( GetProcessHeap(), 0, xpath
);
956 /***********************************************************************
957 * GetCurrentDirectory16 (KERNEL.411)
959 UINT16 WINAPI
GetCurrentDirectory16( UINT16 buflen
, LPSTR buf
)
961 return (UINT16
)GetCurrentDirectoryA( buflen
, buf
);
965 /***********************************************************************
966 * GetCurrentDirectory32A (KERNEL32.196)
968 * Returns "X:\\path\\etc\\".
970 * Despite the API description, return required length including the
971 * terminating null when buffer too small. This is the real behaviour.
973 UINT WINAPI
GetCurrentDirectoryA( UINT buflen
, LPSTR buf
)
976 const char *s
= DRIVE_GetDosCwd( DRIVE_GetCurrentDrive() );
979 ret
= strlen(s
) + 3; /* length of WHOLE current directory */
980 if (ret
>= buflen
) return ret
+ 1;
981 lstrcpynA( buf
, "A:\\", MIN( 4, buflen
) );
982 if (buflen
) buf
[0] += DRIVE_GetCurrentDrive();
983 if (buflen
> 3) lstrcpynA( buf
+ 3, s
, buflen
- 3 );
988 /***********************************************************************
989 * GetCurrentDirectory32W (KERNEL32.197)
991 UINT WINAPI
GetCurrentDirectoryW( UINT buflen
, LPWSTR buf
)
993 LPSTR xpath
= HeapAlloc( GetProcessHeap(), 0, buflen
+1 );
994 UINT ret
= GetCurrentDirectoryA( buflen
, xpath
);
995 lstrcpyAtoW( buf
, xpath
);
996 HeapFree( GetProcessHeap(), 0, xpath
);
1001 /***********************************************************************
1002 * SetCurrentDirectory (KERNEL.412)
1004 BOOL16 WINAPI
SetCurrentDirectory16( LPCSTR dir
)
1006 return SetCurrentDirectoryA( dir
);
1010 /***********************************************************************
1011 * SetCurrentDirectory32A (KERNEL32.479)
1013 BOOL WINAPI
SetCurrentDirectoryA( LPCSTR dir
)
1015 int olddrive
, drive
= DRIVE_GetCurrentDrive();
1018 ERR(file
,"(NULL)!\n");
1021 if (dir
[0] && (dir
[1]==':'))
1023 drive
= tolower( *dir
) - 'a';
1027 /* WARNING: we need to set the drive before the dir, as DRIVE_Chdir
1028 sets pTask->curdir only if pTask->curdrive is drive */
1029 olddrive
= drive
; /* in case DRIVE_Chdir fails */
1030 if (!(DRIVE_SetCurrentDrive( drive
)))
1032 /* FIXME: what about empty strings? Add a \\ ? */
1033 if (!DRIVE_Chdir( drive
, dir
)) {
1034 DRIVE_SetCurrentDrive(olddrive
);
1041 /***********************************************************************
1042 * SetCurrentDirectory32W (KERNEL32.480)
1044 BOOL WINAPI
SetCurrentDirectoryW( LPCWSTR dirW
)
1046 LPSTR dir
= HEAP_strdupWtoA( GetProcessHeap(), 0, dirW
);
1047 BOOL res
= SetCurrentDirectoryA( dir
);
1048 HeapFree( GetProcessHeap(), 0, dir
);
1053 /***********************************************************************
1054 * GetLogicalDriveStrings32A (KERNEL32.231)
1056 UINT WINAPI
GetLogicalDriveStringsA( UINT len
, LPSTR buffer
)
1060 for (drive
= count
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
1061 if (DRIVE_IsValid(drive
)) count
++;
1062 if (count
* 4 * sizeof(char) <= len
)
1065 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
1066 if (DRIVE_IsValid(drive
))
1075 return count
* 4 * sizeof(char);
1079 /***********************************************************************
1080 * GetLogicalDriveStrings32W (KERNEL32.232)
1082 UINT WINAPI
GetLogicalDriveStringsW( UINT len
, LPWSTR buffer
)
1086 for (drive
= count
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
1087 if (DRIVE_IsValid(drive
)) count
++;
1088 if (count
* 4 * sizeof(WCHAR
) <= len
)
1091 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
1092 if (DRIVE_IsValid(drive
))
1094 *p
++ = (WCHAR
)('a' + drive
);
1101 return count
* 4 * sizeof(WCHAR
);
1105 /***********************************************************************
1106 * GetLogicalDrives (KERNEL32.233)
1108 DWORD WINAPI
GetLogicalDrives(void)
1113 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
1114 if (DRIVE_IsValid(drive
)) ret
|= (1 << drive
);
1119 /***********************************************************************
1120 * GetVolumeInformation32A (KERNEL32.309)
1122 BOOL WINAPI
GetVolumeInformationA( LPCSTR root
, LPSTR label
,
1123 DWORD label_len
, DWORD
*serial
,
1124 DWORD
*filename_len
, DWORD
*flags
,
1125 LPSTR fsname
, DWORD fsname_len
)
1130 /* FIXME, SetLastErrors missing */
1132 if (!root
) drive
= DRIVE_GetCurrentDrive();
1135 if ((root
[1]) && (root
[1] != ':'))
1137 WARN(dosfs
, "invalid root '%s'\n",root
);
1140 drive
= toupper(root
[0]) - 'A';
1142 if (!DRIVE_IsValid( drive
)) return FALSE
;
1145 lstrcpynA( label
, DRIVE_GetLabel(drive
), label_len
);
1146 for (cp
= label
; *cp
; cp
++);
1147 while (cp
!= label
&& *(cp
-1) == ' ') cp
--;
1150 if (serial
) *serial
= DRIVE_GetSerialNumber(drive
);
1152 /* Set the filesystem information */
1153 /* Note: we only emulate a FAT fs at the present */
1156 if (DOSDrives
[drive
].flags
& DRIVE_SHORT_NAMES
)
1159 *filename_len
= 255;
1164 if (DOSDrives
[drive
].flags
& DRIVE_CASE_SENSITIVE
)
1165 *flags
|=FS_CASE_SENSITIVE
;
1166 if (DOSDrives
[drive
].flags
& DRIVE_CASE_PRESERVING
)
1167 *flags
|=FS_CASE_IS_PRESERVED
;
1170 /* Diablo checks that return code ... */
1171 if (DRIVE_GetType(drive
)==TYPE_CDROM
)
1172 lstrcpynA( fsname
, "CDFS", fsname_len
);
1174 lstrcpynA( fsname
, "FAT", fsname_len
);
1180 /***********************************************************************
1181 * GetVolumeInformation32W (KERNEL32.310)
1183 BOOL WINAPI
GetVolumeInformationW( LPCWSTR root
, LPWSTR label
,
1184 DWORD label_len
, DWORD
*serial
,
1185 DWORD
*filename_len
, DWORD
*flags
,
1186 LPWSTR fsname
, DWORD fsname_len
)
1188 LPSTR xroot
= HEAP_strdupWtoA( GetProcessHeap(), 0, root
);
1189 LPSTR xvolname
= label
? HeapAlloc(GetProcessHeap(),0,label_len
) : NULL
;
1190 LPSTR xfsname
= fsname
? HeapAlloc(GetProcessHeap(),0,fsname_len
) : NULL
;
1191 BOOL ret
= GetVolumeInformationA( xroot
, xvolname
, label_len
, serial
,
1192 filename_len
, flags
, xfsname
,
1196 if (label
) lstrcpyAtoW( label
, xvolname
);
1197 if (fsname
) lstrcpyAtoW( fsname
, xfsname
);
1199 HeapFree( GetProcessHeap(), 0, xroot
);
1200 HeapFree( GetProcessHeap(), 0, xvolname
);
1201 HeapFree( GetProcessHeap(), 0, xfsname
);
1205 BOOL WINAPI
SetVolumeLabelA(LPCSTR rootpath
,LPCSTR volname
) {
1206 FIXME(dosfs
,"(%s,%s),stub!\n",rootpath
,volname
);