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
->s
.LowPart
= (DWORD
)bigsize
;
682 size
->s
.HighPart
= (DWORD
)(bigsize
>>32);
683 available
->s
.LowPart
= (DWORD
)bigavail
;
684 available
->s
.HighPart
= (DWORD
)(bigavail
>>32);
689 * DRIVE_GetCurrentDirectory
690 * Returns "X:\\path\\etc\\".
692 * Despite the API description, return required length including the
693 * terminating null when buffer too small. This is the real behaviour.
696 static UINT
DRIVE_GetCurrentDirectory( UINT buflen
, LPSTR buf
)
699 const char *s
= DRIVE_GetDosCwd( DRIVE_GetCurrentDrive() );
702 ret
= strlen(s
) + 3; /* length of WHOLE current directory */
703 if (ret
>= buflen
) return ret
+ 1;
704 lstrcpynA( buf
, "A:\\", MIN( 4, buflen
) );
705 if (buflen
) buf
[0] += DRIVE_GetCurrentDrive();
706 if (buflen
> 3) lstrcpynA( buf
+ 3, s
, buflen
- 3 );
710 /***********************************************************************
711 * GetDiskFreeSpace16 (KERNEL.422)
713 BOOL16 WINAPI
GetDiskFreeSpace16( LPCSTR root
, LPDWORD cluster_sectors
,
714 LPDWORD sector_bytes
, LPDWORD free_clusters
,
715 LPDWORD total_clusters
)
717 return GetDiskFreeSpaceA( root
, cluster_sectors
, sector_bytes
,
718 free_clusters
, total_clusters
);
722 /***********************************************************************
723 * GetDiskFreeSpace32A (KERNEL32.206)
725 * Fails if expression resulting from current drive's dir and "root"
726 * is not a root dir of the target drive.
728 * UNDOC: setting some LPDWORDs to NULL is perfectly possible
729 * if the corresponding info is unneeded.
731 * FIXME: needs to support UNC names from Win95 OSR2 on.
733 * Behaviour under Win95a:
734 * CurrDir root result
735 * "E:\\TEST" "E:" FALSE
739 * "E:\\TEST" "\\" TRUE
740 * "E:\\TEST" ":\\" FALSE
741 * "E:\\TEST" "E:\\" TRUE
742 * "E:\\TEST" "" FALSE
743 * "E:\\" "" FALSE (!)
745 * "E:\\TEST" 0x0 TRUE (!)
746 * "E:\\TEST" "C:" TRUE (when CurrDir of "C:" set to "\\")
747 * "E:\\TEST" "C:" FALSE (when CurrDir of "C:" set to "\\TEST")
749 BOOL WINAPI
GetDiskFreeSpaceA( LPCSTR root
, LPDWORD cluster_sectors
,
750 LPDWORD sector_bytes
, LPDWORD free_clusters
,
751 LPDWORD total_clusters
)
754 ULARGE_INTEGER size
,available
;
758 if ((!root
) || (root
== "\\"))
759 drive
= DRIVE_GetCurrentDrive();
761 if ( (strlen(root
) >= 2) && (root
[1] == ':')) /* root contains drive tag */
763 drive
= toupper(root
[0]) - 'A';
766 path
= DRIVE_GetDosCwd(drive
);
770 if (strlen(path
)) /* oops, we are in a subdir */
776 if (!DRIVE_GetFreeSpace(drive
, &size
, &available
)) return FALSE
;
778 /* Cap the size and available at 2GB as per specs. */
779 if ((size
.s
.HighPart
) ||(size
.s
.LowPart
> 0x7fffffff))
782 size
.s
.LowPart
= 0x7fffffff;
784 if ((available
.s
.HighPart
) ||(available
.s
.LowPart
> 0x7fffffff))
786 available
.s
.HighPart
=0;
787 available
.s
.LowPart
= 0x7fffffff;
789 if (DRIVE_GetType(drive
)==TYPE_CDROM
) {
791 *sector_bytes
= 2048;
792 size
.s
.LowPart
/= 2048;
793 available
.s
.LowPart
/= 2048;
797 size
.s
.LowPart
/= 512;
798 available
.s
.LowPart
/= 512;
800 /* fixme: probably have to adjust those variables too for CDFS */
802 while (cluster_sec
* 65536 < size
.s
.LowPart
) cluster_sec
*= 2;
805 *cluster_sectors
= cluster_sec
;
807 *free_clusters
= available
.s
.LowPart
/ cluster_sec
;
809 *total_clusters
= size
.s
.LowPart
/ cluster_sec
;
814 /***********************************************************************
815 * GetDiskFreeSpace32W (KERNEL32.207)
817 BOOL WINAPI
GetDiskFreeSpaceW( LPCWSTR root
, LPDWORD cluster_sectors
,
818 LPDWORD sector_bytes
, LPDWORD free_clusters
,
819 LPDWORD total_clusters
)
824 xroot
= HEAP_strdupWtoA( GetProcessHeap(), 0, root
);
825 ret
= GetDiskFreeSpaceA( xroot
,cluster_sectors
, sector_bytes
,
826 free_clusters
, total_clusters
);
827 HeapFree( GetProcessHeap(), 0, xroot
);
832 /***********************************************************************
833 * GetDiskFreeSpaceEx32A (KERNEL32.871)
835 * This function is used to aquire the size of the available and
836 * total space on a logical volume.
840 * Zero on failure, nonzero upon success. Use GetLastError to obtain
841 * detailed error information.
844 BOOL WINAPI
GetDiskFreeSpaceExA( LPCSTR root
,
845 PULARGE_INTEGER avail
,
846 PULARGE_INTEGER total
,
847 PULARGE_INTEGER totalfree
)
850 ULARGE_INTEGER size
,available
;
852 if (!root
) drive
= DRIVE_GetCurrentDrive();
855 if ((root
[1]) && ((root
[1] != ':') || (root
[2] != '\\')))
857 FIXME_(dosfs
)("there are valid root names which are not supported yet\n");
858 /* ..like UNC names, for instance. */
860 WARN_(dosfs
)("invalid root '%s'\n", root
);
863 drive
= toupper(root
[0]) - 'A';
866 if (!DRIVE_GetFreeSpace(drive
, &size
, &available
)) return FALSE
;
870 total
->s
.HighPart
= size
.s
.HighPart
;
871 total
->s
.LowPart
= size
.s
.LowPart
;
876 totalfree
->s
.HighPart
= available
.s
.HighPart
;
877 totalfree
->s
.LowPart
= available
.s
.LowPart
;
884 /* On Windows2000, we need to check the disk quota
885 allocated for the user owning the calling process. We
886 don't want to be more obtrusive than necessary with the
887 FIXME messages, so don't print the FIXME unless Wine is
888 actually masquerading as Windows2000. */
891 ovi
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOA
);
892 if (GetVersionExA(&ovi
))
894 if (ovi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
&& ovi
.dwMajorVersion
> 4)
895 FIXME_(dosfs
)("no per-user quota support yet\n");
899 /* Quick hack, should eventually be fixed to work 100% with
900 Windows2000 (see comment above). */
901 avail
->s
.HighPart
= available
.s
.HighPart
;
902 avail
->s
.LowPart
= available
.s
.LowPart
;
908 /***********************************************************************
909 * GetDiskFreeSpaceEx32W (KERNEL32.873)
911 BOOL WINAPI
GetDiskFreeSpaceExW( LPCWSTR root
, PULARGE_INTEGER avail
,
912 PULARGE_INTEGER total
,
913 PULARGE_INTEGER totalfree
)
918 xroot
= HEAP_strdupWtoA( GetProcessHeap(), 0, root
);
919 ret
= GetDiskFreeSpaceExA( xroot
, avail
, total
, totalfree
);
920 HeapFree( GetProcessHeap(), 0, xroot
);
924 /***********************************************************************
925 * GetDriveType16 (KERNEL.136)
926 * This functions returns the drivetype of a drive in Win16.
927 * Note that it returns DRIVE_REMOTE for CD-ROMs, since MSCDEX uses the
928 * remote drive API. The returnvalue DRIVE_REMOTE for CD-ROMs has been
929 * verified on Win3.11 and Windows 95. Some programs rely on it, so don't
930 * do any pseudo-clever changes.
933 * drivetype DRIVE_xxx
935 UINT16 WINAPI
GetDriveType16(
936 UINT16 drive
/* [in] number (NOT letter) of drive */
938 TRACE_(dosfs
)("(%c:)\n", 'A' + drive
);
939 switch(DRIVE_GetType(drive
))
941 case TYPE_FLOPPY
: return DRIVE_REMOVABLE
;
942 case TYPE_HD
: return DRIVE_FIXED
;
943 case TYPE_CDROM
: return DRIVE_REMOTE
;
944 case TYPE_NETWORK
: return DRIVE_REMOTE
;
946 default: return DRIVE_CANNOTDETERMINE
;
951 /***********************************************************************
952 * GetDriveType32A (KERNEL32.208)
954 * Returns the type of the disk drive specified. If root is NULL the
955 * root of the current directory is used.
959 * Type of drive (from Win32 SDK):
961 * DRIVE_UNKNOWN unable to find out anything about the drive
962 * DRIVE_NO_ROOT_DIR nonexistand root dir
963 * DRIVE_REMOVABLE the disk can be removed from the machine
964 * DRIVE_FIXED the disk can not be removed from the machine
965 * DRIVE_REMOTE network disk
966 * DRIVE_CDROM CDROM drive
967 * DRIVE_RAMDISK virtual disk in ram
969 * DRIVE_DOESNOTEXIST XXX Not valid return value
970 * DRIVE_CANNOTDETERMINE XXX Not valid return value
974 * Currently returns DRIVE_DOESNOTEXIST and DRIVE_CANNOTDETERMINE
975 * when it really should return DRIVE_NO_ROOT_DIR and DRIVE_UNKNOWN.
976 * Why where the former defines used?
978 * DRIVE_RAMDISK is unsupported.
980 UINT WINAPI
GetDriveTypeA(LPCSTR root
/* String describing drive */)
983 TRACE_(dosfs
)("(%s)\n", debugstr_a(root
));
985 if (NULL
== root
) drive
= DRIVE_GetCurrentDrive();
988 if ((root
[1]) && (root
[1] != ':'))
990 WARN_(dosfs
)("invalid root '%s'\n", debugstr_a(root
));
991 return DRIVE_DOESNOTEXIST
;
993 drive
= toupper(root
[0]) - 'A';
995 switch(DRIVE_GetType(drive
))
997 case TYPE_FLOPPY
: return DRIVE_REMOVABLE
;
998 case TYPE_HD
: return DRIVE_FIXED
;
999 case TYPE_CDROM
: return DRIVE_CDROM
;
1000 case TYPE_NETWORK
: return DRIVE_REMOTE
;
1001 case TYPE_INVALID
: return DRIVE_DOESNOTEXIST
;
1002 default: return DRIVE_CANNOTDETERMINE
;
1007 /***********************************************************************
1008 * GetDriveType32W (KERNEL32.209)
1010 UINT WINAPI
GetDriveTypeW( LPCWSTR root
)
1012 LPSTR xpath
= HEAP_strdupWtoA( GetProcessHeap(), 0, root
);
1013 UINT ret
= GetDriveTypeA( xpath
);
1014 HeapFree( GetProcessHeap(), 0, xpath
);
1019 /***********************************************************************
1020 * GetCurrentDirectory16 (KERNEL.411)
1022 UINT16 WINAPI
GetCurrentDirectory16( UINT16 buflen
, LPSTR buf
)
1024 return (UINT16
)DRIVE_GetCurrentDirectory(buflen
, buf
);
1028 /***********************************************************************
1029 * GetCurrentDirectory32A (KERNEL32.196)
1031 UINT WINAPI
GetCurrentDirectoryA( UINT buflen
, LPSTR buf
)
1034 char longname
[MAX_PATHNAME_LEN
];
1036 ret
= DRIVE_GetCurrentDirectory(buflen
, buf
);
1037 GetLongPathNameA(buf
, longname
, buflen
);
1038 lstrcpyA(buf
, longname
);
1043 /***********************************************************************
1044 * GetCurrentDirectory32W (KERNEL32.197)
1046 UINT WINAPI
GetCurrentDirectoryW( UINT buflen
, LPWSTR buf
)
1048 LPSTR xpath
= HeapAlloc( GetProcessHeap(), 0, buflen
+1 );
1049 UINT ret
= GetCurrentDirectoryA( buflen
, xpath
);
1050 lstrcpyAtoW( buf
, xpath
);
1051 HeapFree( GetProcessHeap(), 0, xpath
);
1056 /***********************************************************************
1057 * SetCurrentDirectory (KERNEL.412)
1059 BOOL16 WINAPI
SetCurrentDirectory16( LPCSTR dir
)
1061 return SetCurrentDirectoryA( dir
);
1065 /***********************************************************************
1066 * SetCurrentDirectory32A (KERNEL32.479)
1068 BOOL WINAPI
SetCurrentDirectoryA( LPCSTR dir
)
1070 int olddrive
, drive
= DRIVE_GetCurrentDrive();
1073 ERR_(file
)("(NULL)!\n");
1076 if (dir
[0] && (dir
[1]==':'))
1078 drive
= tolower( *dir
) - 'a';
1082 /* WARNING: we need to set the drive before the dir, as DRIVE_Chdir
1083 sets pTask->curdir only if pTask->curdrive is drive */
1084 olddrive
= drive
; /* in case DRIVE_Chdir fails */
1085 if (!(DRIVE_SetCurrentDrive( drive
)))
1087 /* FIXME: what about empty strings? Add a \\ ? */
1088 if (!DRIVE_Chdir( drive
, dir
)) {
1089 DRIVE_SetCurrentDrive(olddrive
);
1096 /***********************************************************************
1097 * SetCurrentDirectory32W (KERNEL32.480)
1099 BOOL WINAPI
SetCurrentDirectoryW( LPCWSTR dirW
)
1101 LPSTR dir
= HEAP_strdupWtoA( GetProcessHeap(), 0, dirW
);
1102 BOOL res
= SetCurrentDirectoryA( dir
);
1103 HeapFree( GetProcessHeap(), 0, dir
);
1108 /***********************************************************************
1109 * GetLogicalDriveStrings32A (KERNEL32.231)
1111 UINT WINAPI
GetLogicalDriveStringsA( UINT len
, LPSTR buffer
)
1115 for (drive
= count
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
1116 if (DRIVE_IsValid(drive
)) count
++;
1117 if ((count
* 4) + 1 <= len
)
1120 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
1121 if (DRIVE_IsValid(drive
))
1132 return (count
* 4) + 1;/* account for terminating null */
1133 /* The API tells about these different return values */
1137 /***********************************************************************
1138 * GetLogicalDriveStrings32W (KERNEL32.232)
1140 UINT WINAPI
GetLogicalDriveStringsW( UINT len
, LPWSTR buffer
)
1144 for (drive
= count
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
1145 if (DRIVE_IsValid(drive
)) count
++;
1146 if (count
* 4 * sizeof(WCHAR
) <= len
)
1149 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
1150 if (DRIVE_IsValid(drive
))
1152 *p
++ = (WCHAR
)('a' + drive
);
1159 return count
* 4 * sizeof(WCHAR
);
1163 /***********************************************************************
1164 * GetLogicalDrives (KERNEL32.233)
1166 DWORD WINAPI
GetLogicalDrives(void)
1171 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
1172 if (DRIVE_IsValid(drive
)) ret
|= (1 << drive
);
1177 /***********************************************************************
1178 * GetVolumeInformation32A (KERNEL32.309)
1180 BOOL WINAPI
GetVolumeInformationA( LPCSTR root
, LPSTR label
,
1181 DWORD label_len
, DWORD
*serial
,
1182 DWORD
*filename_len
, DWORD
*flags
,
1183 LPSTR fsname
, DWORD fsname_len
)
1188 /* FIXME, SetLastErrors missing */
1190 if (!root
) drive
= DRIVE_GetCurrentDrive();
1193 if ((root
[1]) && (root
[1] != ':'))
1195 WARN_(dosfs
)("invalid root '%s'\n",root
);
1198 drive
= toupper(root
[0]) - 'A';
1200 if (!DRIVE_IsValid( drive
)) return FALSE
;
1203 lstrcpynA( label
, DRIVE_GetLabel(drive
), label_len
);
1204 for (cp
= label
; *cp
; cp
++);
1205 while (cp
!= label
&& *(cp
-1) == ' ') cp
--;
1208 if (serial
) *serial
= DRIVE_GetSerialNumber(drive
);
1210 /* Set the filesystem information */
1211 /* Note: we only emulate a FAT fs at the present */
1214 if (DOSDrives
[drive
].flags
& DRIVE_SHORT_NAMES
)
1217 *filename_len
= 255;
1222 if (DOSDrives
[drive
].flags
& DRIVE_CASE_SENSITIVE
)
1223 *flags
|=FS_CASE_SENSITIVE
;
1224 if (DOSDrives
[drive
].flags
& DRIVE_CASE_PRESERVING
)
1225 *flags
|=FS_CASE_IS_PRESERVED
;
1228 /* Diablo checks that return code ... */
1229 if (DRIVE_GetType(drive
)==TYPE_CDROM
)
1230 lstrcpynA( fsname
, "CDFS", fsname_len
);
1232 lstrcpynA( fsname
, "FAT", fsname_len
);
1238 /***********************************************************************
1239 * GetVolumeInformation32W (KERNEL32.310)
1241 BOOL WINAPI
GetVolumeInformationW( LPCWSTR root
, LPWSTR label
,
1242 DWORD label_len
, DWORD
*serial
,
1243 DWORD
*filename_len
, DWORD
*flags
,
1244 LPWSTR fsname
, DWORD fsname_len
)
1246 LPSTR xroot
= HEAP_strdupWtoA( GetProcessHeap(), 0, root
);
1247 LPSTR xvolname
= label
? HeapAlloc(GetProcessHeap(),0,label_len
) : NULL
;
1248 LPSTR xfsname
= fsname
? HeapAlloc(GetProcessHeap(),0,fsname_len
) : NULL
;
1249 BOOL ret
= GetVolumeInformationA( xroot
, xvolname
, label_len
, serial
,
1250 filename_len
, flags
, xfsname
,
1254 if (label
) lstrcpyAtoW( label
, xvolname
);
1255 if (fsname
) lstrcpyAtoW( fsname
, xfsname
);
1257 HeapFree( GetProcessHeap(), 0, xroot
);
1258 HeapFree( GetProcessHeap(), 0, xvolname
);
1259 HeapFree( GetProcessHeap(), 0, xfsname
);
1263 /***********************************************************************
1264 * SetVolumeLabelA (KERNEL32.675)
1266 BOOL WINAPI
SetVolumeLabelA(LPCSTR rootpath
,LPCSTR volname
)
1268 FIXME_(dosfs
)("(%s,%s),stub!\n",rootpath
,volname
);
1272 /***********************************************************************
1273 * SetVolumeLabelW (KERNEL32.676)
1275 BOOL WINAPI
SetVolumeLabelW(LPCWSTR rootpath
,LPCWSTR volname
)
1280 xroot
= HEAP_strdupWtoA( GetProcessHeap(), 0, rootpath
);
1281 xvol
= HEAP_strdupWtoA( GetProcessHeap(), 0, volname
);
1282 ret
= SetVolumeLabelA( xroot
, xvol
);
1283 HeapFree( GetProcessHeap(), 0, xroot
);
1284 HeapFree( GetProcessHeap(), 0, xvol
);