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 */
45 #include "debugtools.h"
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 MESSAGE("%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 MESSAGE("%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 MESSAGE("Could not stat %s, ignoring drive %c:\n", path
, 'A' + i
);
160 if (!S_ISDIR(drive_stat_buffer
.st_mode
))
162 MESSAGE("%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 MESSAGE("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 * This function is used to aquire the size of the available and
815 * total space on a logical volume.
819 * Zero on failure, nonzero upon success. Use GetLastError to obtain
820 * detailed error information.
823 BOOL WINAPI
GetDiskFreeSpaceExA( LPCSTR root
,
824 PULARGE_INTEGER avail
,
825 PULARGE_INTEGER total
,
826 PULARGE_INTEGER totalfree
)
829 ULARGE_INTEGER size
,available
;
831 if (!root
) drive
= DRIVE_GetCurrentDrive();
834 if ((root
[1]) && ((root
[1] != ':') || (root
[2] != '\\')))
836 FIXME_(dosfs
)("there are valid root names which are not supported yet\n");
837 /* ..like UNC names, for instance. */
839 WARN_(dosfs
)("invalid root '%s'\n", root
);
842 drive
= toupper(root
[0]) - 'A';
845 if (!DRIVE_GetFreeSpace(drive
, &size
, &available
)) return FALSE
;
849 total
->HighPart
= size
.HighPart
;
850 total
->LowPart
= size
.LowPart
;
855 totalfree
->HighPart
= available
.HighPart
;
856 totalfree
->LowPart
= available
.LowPart
;
863 /* On Windows2000, we need to check the disk quota
864 allocated for the user owning the calling process. We
865 don't want to be more obtrusive than necessary with the
866 FIXME messages, so don't print the FIXME unless Wine is
867 actually masquerading as Windows2000. */
870 ovi
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOA
);
871 if (GetVersionExA(&ovi
))
873 if (ovi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
&& ovi
.dwMajorVersion
> 4)
874 FIXME_(dosfs
)("no per-user quota support yet\n");
878 /* Quick hack, should eventually be fixed to work 100% with
879 Windows2000 (see comment above). */
880 avail
->HighPart
= totalfree
->HighPart
;
881 avail
->LowPart
= totalfree
->LowPart
;
887 /***********************************************************************
888 * GetDiskFreeSpaceEx32W (KERNEL32.873)
890 BOOL WINAPI
GetDiskFreeSpaceExW( LPCWSTR root
, PULARGE_INTEGER avail
,
891 PULARGE_INTEGER total
,
892 PULARGE_INTEGER totalfree
)
897 xroot
= HEAP_strdupWtoA( GetProcessHeap(), 0, root
);
898 ret
= GetDiskFreeSpaceExA( xroot
, avail
, total
, totalfree
);
899 HeapFree( GetProcessHeap(), 0, xroot
);
903 /***********************************************************************
904 * GetDriveType16 (KERNEL.136)
905 * This functions returns the drivetype of a drive in Win16.
906 * Note that it returns DRIVE_REMOTE for CD-ROMs, since MSCDEX uses the
907 * remote drive API. The returnvalue DRIVE_REMOTE for CD-ROMs has been
908 * verified on Win3.11 and Windows 95. Some programs rely on it, so don't
909 * do any pseudo-clever changes.
912 * drivetype DRIVE_xxx
914 UINT16 WINAPI
GetDriveType16(
915 UINT16 drive
/* [in] number (NOT letter) of drive */
917 TRACE_(dosfs
)("(%c:)\n", 'A' + drive
);
918 switch(DRIVE_GetType(drive
))
920 case TYPE_FLOPPY
: return DRIVE_REMOVABLE
;
921 case TYPE_HD
: return DRIVE_FIXED
;
922 case TYPE_CDROM
: return DRIVE_REMOTE
;
923 case TYPE_NETWORK
: return DRIVE_REMOTE
;
925 default: return DRIVE_CANNOTDETERMINE
;
930 /***********************************************************************
931 * GetDriveType32A (KERNEL32.208)
933 * Returns the type of the disk drive specified. If root is NULL the
934 * root of the current directory is used.
938 * Type of drive (from Win32 SDK):
940 * DRIVE_UNKNOWN unable to find out anything about the drive
941 * DRIVE_NO_ROOT_DIR nonexistand root dir
942 * DRIVE_REMOVABLE the disk can be removed from the machine
943 * DRIVE_FIXED the disk can not be removed from the machine
944 * DRIVE_REMOTE network disk
945 * DRIVE_CDROM CDROM drive
946 * DRIVE_RAMDISK virtual disk in ram
948 * DRIVE_DOESNOTEXIST XXX Not valid return value
949 * DRIVE_CANNOTDETERMINE XXX Not valid return value
953 * Currently returns DRIVE_DOESNOTEXIST and DRIVE_CANNOTDETERMINE
954 * when it really should return DRIVE_NO_ROOT_DIR and DRIVE_UNKNOWN.
955 * Why where the former defines used?
957 * DRIVE_RAMDISK is unsupported.
959 UINT WINAPI
GetDriveTypeA(LPCSTR root
/* String describing drive */)
962 TRACE_(dosfs
)("(%s)\n", debugstr_a(root
));
964 if (NULL
== root
) drive
= DRIVE_GetCurrentDrive();
967 if ((root
[1]) && (root
[1] != ':'))
969 WARN_(dosfs
)("invalid root '%s'\n", debugstr_a(root
));
970 return DRIVE_DOESNOTEXIST
;
972 drive
= toupper(root
[0]) - 'A';
974 switch(DRIVE_GetType(drive
))
976 case TYPE_FLOPPY
: return DRIVE_REMOVABLE
;
977 case TYPE_HD
: return DRIVE_FIXED
;
978 case TYPE_CDROM
: return DRIVE_CDROM
;
979 case TYPE_NETWORK
: return DRIVE_REMOTE
;
980 case TYPE_INVALID
: return DRIVE_DOESNOTEXIST
;
981 default: return DRIVE_CANNOTDETERMINE
;
986 /***********************************************************************
987 * GetDriveType32W (KERNEL32.209)
989 UINT WINAPI
GetDriveTypeW( LPCWSTR root
)
991 LPSTR xpath
= HEAP_strdupWtoA( GetProcessHeap(), 0, root
);
992 UINT ret
= GetDriveTypeA( xpath
);
993 HeapFree( GetProcessHeap(), 0, xpath
);
998 /***********************************************************************
999 * GetCurrentDirectory16 (KERNEL.411)
1001 UINT16 WINAPI
GetCurrentDirectory16( UINT16 buflen
, LPSTR buf
)
1003 return (UINT16
)GetCurrentDirectoryA( buflen
, buf
);
1007 /***********************************************************************
1008 * GetCurrentDirectory32A (KERNEL32.196)
1010 * Returns "X:\\path\\etc\\".
1012 * Despite the API description, return required length including the
1013 * terminating null when buffer too small. This is the real behaviour.
1015 UINT WINAPI
GetCurrentDirectoryA( UINT buflen
, LPSTR buf
)
1018 const char *s
= DRIVE_GetDosCwd( DRIVE_GetCurrentDrive() );
1021 ret
= strlen(s
) + 3; /* length of WHOLE current directory */
1022 if (ret
>= buflen
) return ret
+ 1;
1023 lstrcpynA( buf
, "A:\\", MIN( 4, buflen
) );
1024 if (buflen
) buf
[0] += DRIVE_GetCurrentDrive();
1025 if (buflen
> 3) lstrcpynA( buf
+ 3, s
, buflen
- 3 );
1030 /***********************************************************************
1031 * GetCurrentDirectory32W (KERNEL32.197)
1033 UINT WINAPI
GetCurrentDirectoryW( UINT buflen
, LPWSTR buf
)
1035 LPSTR xpath
= HeapAlloc( GetProcessHeap(), 0, buflen
+1 );
1036 UINT ret
= GetCurrentDirectoryA( buflen
, xpath
);
1037 lstrcpyAtoW( buf
, xpath
);
1038 HeapFree( GetProcessHeap(), 0, xpath
);
1043 /***********************************************************************
1044 * SetCurrentDirectory (KERNEL.412)
1046 BOOL16 WINAPI
SetCurrentDirectory16( LPCSTR dir
)
1048 return SetCurrentDirectoryA( dir
);
1052 /***********************************************************************
1053 * SetCurrentDirectory32A (KERNEL32.479)
1055 BOOL WINAPI
SetCurrentDirectoryA( LPCSTR dir
)
1057 int olddrive
, drive
= DRIVE_GetCurrentDrive();
1060 ERR_(file
)("(NULL)!\n");
1063 if (dir
[0] && (dir
[1]==':'))
1065 drive
= tolower( *dir
) - 'a';
1069 /* WARNING: we need to set the drive before the dir, as DRIVE_Chdir
1070 sets pTask->curdir only if pTask->curdrive is drive */
1071 olddrive
= drive
; /* in case DRIVE_Chdir fails */
1072 if (!(DRIVE_SetCurrentDrive( drive
)))
1074 /* FIXME: what about empty strings? Add a \\ ? */
1075 if (!DRIVE_Chdir( drive
, dir
)) {
1076 DRIVE_SetCurrentDrive(olddrive
);
1083 /***********************************************************************
1084 * SetCurrentDirectory32W (KERNEL32.480)
1086 BOOL WINAPI
SetCurrentDirectoryW( LPCWSTR dirW
)
1088 LPSTR dir
= HEAP_strdupWtoA( GetProcessHeap(), 0, dirW
);
1089 BOOL res
= SetCurrentDirectoryA( dir
);
1090 HeapFree( GetProcessHeap(), 0, dir
);
1095 /***********************************************************************
1096 * GetLogicalDriveStrings32A (KERNEL32.231)
1098 UINT WINAPI
GetLogicalDriveStringsA( UINT len
, LPSTR buffer
)
1102 for (drive
= count
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
1103 if (DRIVE_IsValid(drive
)) count
++;
1104 if (count
* 4 * sizeof(char) <= len
)
1107 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
1108 if (DRIVE_IsValid(drive
))
1117 return count
* 4 * sizeof(char);
1121 /***********************************************************************
1122 * GetLogicalDriveStrings32W (KERNEL32.232)
1124 UINT WINAPI
GetLogicalDriveStringsW( UINT len
, LPWSTR buffer
)
1128 for (drive
= count
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
1129 if (DRIVE_IsValid(drive
)) count
++;
1130 if (count
* 4 * sizeof(WCHAR
) <= len
)
1133 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
1134 if (DRIVE_IsValid(drive
))
1136 *p
++ = (WCHAR
)('a' + drive
);
1143 return count
* 4 * sizeof(WCHAR
);
1147 /***********************************************************************
1148 * GetLogicalDrives (KERNEL32.233)
1150 DWORD WINAPI
GetLogicalDrives(void)
1155 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
1156 if (DRIVE_IsValid(drive
)) ret
|= (1 << drive
);
1161 /***********************************************************************
1162 * GetVolumeInformation32A (KERNEL32.309)
1164 BOOL WINAPI
GetVolumeInformationA( LPCSTR root
, LPSTR label
,
1165 DWORD label_len
, DWORD
*serial
,
1166 DWORD
*filename_len
, DWORD
*flags
,
1167 LPSTR fsname
, DWORD fsname_len
)
1172 /* FIXME, SetLastErrors missing */
1174 if (!root
) drive
= DRIVE_GetCurrentDrive();
1177 if ((root
[1]) && (root
[1] != ':'))
1179 WARN_(dosfs
)("invalid root '%s'\n",root
);
1182 drive
= toupper(root
[0]) - 'A';
1184 if (!DRIVE_IsValid( drive
)) return FALSE
;
1187 lstrcpynA( label
, DRIVE_GetLabel(drive
), label_len
);
1188 for (cp
= label
; *cp
; cp
++);
1189 while (cp
!= label
&& *(cp
-1) == ' ') cp
--;
1192 if (serial
) *serial
= DRIVE_GetSerialNumber(drive
);
1194 /* Set the filesystem information */
1195 /* Note: we only emulate a FAT fs at the present */
1198 if (DOSDrives
[drive
].flags
& DRIVE_SHORT_NAMES
)
1201 *filename_len
= 255;
1206 if (DOSDrives
[drive
].flags
& DRIVE_CASE_SENSITIVE
)
1207 *flags
|=FS_CASE_SENSITIVE
;
1208 if (DOSDrives
[drive
].flags
& DRIVE_CASE_PRESERVING
)
1209 *flags
|=FS_CASE_IS_PRESERVED
;
1212 /* Diablo checks that return code ... */
1213 if (DRIVE_GetType(drive
)==TYPE_CDROM
)
1214 lstrcpynA( fsname
, "CDFS", fsname_len
);
1216 lstrcpynA( fsname
, "FAT", fsname_len
);
1222 /***********************************************************************
1223 * GetVolumeInformation32W (KERNEL32.310)
1225 BOOL WINAPI
GetVolumeInformationW( LPCWSTR root
, LPWSTR label
,
1226 DWORD label_len
, DWORD
*serial
,
1227 DWORD
*filename_len
, DWORD
*flags
,
1228 LPWSTR fsname
, DWORD fsname_len
)
1230 LPSTR xroot
= HEAP_strdupWtoA( GetProcessHeap(), 0, root
);
1231 LPSTR xvolname
= label
? HeapAlloc(GetProcessHeap(),0,label_len
) : NULL
;
1232 LPSTR xfsname
= fsname
? HeapAlloc(GetProcessHeap(),0,fsname_len
) : NULL
;
1233 BOOL ret
= GetVolumeInformationA( xroot
, xvolname
, label_len
, serial
,
1234 filename_len
, flags
, xfsname
,
1238 if (label
) lstrcpyAtoW( label
, xvolname
);
1239 if (fsname
) lstrcpyAtoW( fsname
, xfsname
);
1241 HeapFree( GetProcessHeap(), 0, xroot
);
1242 HeapFree( GetProcessHeap(), 0, xvolname
);
1243 HeapFree( GetProcessHeap(), 0, xfsname
);
1247 /***********************************************************************
1248 * SetVolumeLabelA (KERNEL32.675)
1250 BOOL WINAPI
SetVolumeLabelA(LPCSTR rootpath
,LPCSTR volname
)
1252 FIXME_(dosfs
)("(%s,%s),stub!\n",rootpath
,volname
);
1256 /***********************************************************************
1257 * SetVolumeLabelW (KERNEL32.676)
1259 BOOL WINAPI
SetVolumeLabelW(LPCWSTR rootpath
,LPCWSTR volname
)
1264 xroot
= HEAP_strdupWtoA( GetProcessHeap(), 0, rootpath
);
1265 xvol
= HEAP_strdupWtoA( GetProcessHeap(), 0, volname
);
1266 ret
= SetVolumeLabelA( xroot
, xvol
);
1267 HeapFree( GetProcessHeap(), 0, xroot
);
1268 HeapFree( GetProcessHeap(), 0, xvol
);