2 * DOS drives handling functions
4 * Copyright 1993 Erik Bos
5 * Copyright 1996 Alexandre Julliard
10 #include <sys/types.h>
13 #if defined(__linux__) || defined(sun)
16 #if defined(__NetBSD__) || defined(__FreeBSD__)
17 #include <sys/param.h>
18 #include <sys/mount.h>
19 #include <sys/errno.h>
21 #if defined(__svr4__) || defined(_SCO_DS)
22 #include <sys/statfs.h>
38 char *root
; /* root dir in Unix format without trailing / */
39 char *dos_cwd
; /* cwd in DOS format without leading or trailing \ */
40 char *unix_cwd
; /* cwd in Unix format without leading or trailing / */
41 char label
[12]; /* drive label */
42 DWORD serial
; /* drive serial number */
43 DRIVETYPE type
; /* drive type */
44 BYTE disabled
; /* disabled flag */
48 static const char *DRIVE_Types
[] =
50 "floppy", /* TYPE_FLOPPY */
52 "cdrom", /* TYPE_CDROM */
53 "network" /* TYPE_NETWORK */
57 static DOSDRIVE DOSDrives
[MAX_DOS_DRIVES
];
58 static int DRIVE_CurDrive
= -1;
60 static HTASK DRIVE_LastTask
= 0;
63 /***********************************************************************
66 static DRIVETYPE
DRIVE_GetDriveType( const char *name
)
71 PROFILE_GetWineIniString( name
, "Type", "hd", buffer
, sizeof(buffer
) );
72 for (i
= 0; i
< sizeof(DRIVE_Types
)/sizeof(DRIVE_Types
[0]); i
++)
74 if (!lstrcmpi( buffer
, DRIVE_Types
[i
] )) return (DRIVETYPE
)i
;
76 fprintf( stderr
, "%s: unknown type '%s', defaulting to 'hd'.\n",
82 /***********************************************************************
87 int i
, len
, count
= 0;
88 char name
[] = "Drive A";
89 char path
[MAX_PATHNAME_LEN
];
94 for (i
= 0, drive
= DOSDrives
; i
< MAX_DOS_DRIVES
; i
++, name
[6]++, drive
++)
96 PROFILE_GetWineIniString( name
, "Path", "", path
, sizeof(path
)-1 );
99 p
= path
+ strlen(path
) - 1;
100 while ((p
> path
) && ((*p
== '/') || (*p
== '\\'))) *p
-- = '\0';
101 drive
->root
= xstrdup( path
);
102 drive
->dos_cwd
= xstrdup( "" );
103 drive
->unix_cwd
= xstrdup( "" );
104 drive
->type
= DRIVE_GetDriveType( name
);
107 /* Get the drive label */
108 PROFILE_GetWineIniString( name
, "Label", name
, drive
->label
, 12 );
109 if ((len
= strlen(drive
->label
)) < 11)
111 /* Pad label with spaces */
112 memset( drive
->label
+ len
, ' ', 11 - len
);
113 drive
->label
[12] = '\0';
116 /* Get the serial number */
117 PROFILE_GetWineIniString( name
, "Serial", "12345678",
118 buffer
, sizeof(buffer
) );
119 drive
->serial
= strtoul( buffer
, NULL
, 16 );
121 /* Make the first hard disk the current drive */
122 if ((DRIVE_CurDrive
== -1) && (drive
->type
== TYPE_HD
))
126 dprintf_dosfs( stddeb
, "%s: path=%s type=%s label='%s' serial=%08lx\n",
127 name
, path
, DRIVE_Types
[drive
->type
],
128 drive
->label
, drive
->serial
);
130 else dprintf_dosfs( stddeb
, "%s: not defined\n", name
);
135 fprintf( stderr
, "Warning: no valid DOS drive found, check your configuration file.\n" );
136 /* Create a C drive pointing to Unix root dir */
137 DOSDrives
[2].root
= xstrdup( "/" );
138 DOSDrives
[2].dos_cwd
= xstrdup( "" );
139 DOSDrives
[2].unix_cwd
= xstrdup( "" );
140 strcpy( DOSDrives
[2].label
, "Drive C " );
141 DOSDrives
[2].serial
= 0x12345678;
142 DOSDrives
[2].type
= TYPE_HD
;
143 DOSDrives
[2].disabled
= 0;
147 /* Make sure the current drive is valid */
148 if (DRIVE_CurDrive
== -1)
150 for (i
= 0, drive
= DOSDrives
; i
< MAX_DOS_DRIVES
; i
++, drive
++)
152 if (drive
->root
&& !drive
->disabled
)
164 /***********************************************************************
167 int DRIVE_IsValid( int drive
)
169 if ((drive
< 0) || (drive
>= MAX_DOS_DRIVES
)) return 0;
170 return (DOSDrives
[drive
].root
&& !DOSDrives
[drive
].disabled
);
174 /***********************************************************************
175 * DRIVE_GetCurrentDrive
177 int DRIVE_GetCurrentDrive(void)
179 TDB
*pTask
= (TDB
*)GlobalLock16( GetCurrentTask() );
180 if (pTask
&& (pTask
->curdrive
& 0x80)) return pTask
->curdrive
& ~0x80;
181 return DRIVE_CurDrive
;
185 /***********************************************************************
186 * DRIVE_SetCurrentDrive
188 int DRIVE_SetCurrentDrive( int drive
)
190 TDB
*pTask
= (TDB
*)GlobalLock16( GetCurrentTask() );
191 if (!DRIVE_IsValid( drive
))
193 DOS_ERROR( ER_InvalidDrive
, EC_MediaError
, SA_Abort
, EL_Disk
);
196 dprintf_dosfs( stddeb
, "DRIVE_SetCurrentDrive: %c:\n", 'A' + drive
);
197 DRIVE_CurDrive
= drive
;
198 if (pTask
) pTask
->curdrive
= drive
| 0x80;
203 /***********************************************************************
204 * DRIVE_FindDriveRoot
206 * Find a drive for which the root matches the begginning of the given path.
207 * This can be used to translate a Unix path into a drive + DOS path.
208 * Return value is the drive, or -1 on error. On success, path is modified
209 * to point to the beginning of the DOS path.
210 * FIXME: this only does a textual comparison of the path names, and won't
211 * work well in the presence of symbolic links.
213 int DRIVE_FindDriveRoot( const char **path
)
215 int drive
, rootdrive
= -1;
218 dprintf_dosfs( stddeb
, "DRIVE_FindDriveRoot: searching '%s'\n", *path
);
219 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
221 if (!DOSDrives
[drive
].root
|| DOSDrives
[drive
].disabled
) continue;
223 p2
= DOSDrives
[drive
].root
;
224 dprintf_dosfs( stddeb
, "DRIVE_FindDriveRoot: checking %c: '%s'\n",
227 while (*p2
== '/') p2
++;
231 continue; /* Look if there's a better match */
235 while ((*p1
== '\\') || (*p1
== '/')) p1
++;
236 while (*p2
== '/') p2
++;
237 while ((*p1
== *p2
) && (*p2
) && (*p2
!= '/')) p1
++, p2
++;
240 if (IS_END_OF_NAME(*p1
)) /* OK, found it */
248 if (IS_END_OF_NAME(*p1
))
249 continue; /* Go to next path element */
251 break; /* No match, go to next drive */
258 /***********************************************************************
261 const char * DRIVE_GetRoot( int drive
)
263 if (!DRIVE_IsValid( drive
)) return NULL
;
264 return DOSDrives
[drive
].root
;
268 /***********************************************************************
271 const char * DRIVE_GetDosCwd( int drive
)
273 TDB
*pTask
= (TDB
*)GlobalLock16( GetCurrentTask() );
274 if (!DRIVE_IsValid( drive
)) return NULL
;
276 /* Check if we need to change the directory to the new task. */
277 if (pTask
&& (pTask
->curdrive
& 0x80) && /* The task drive is valid */
278 ((pTask
->curdrive
& ~0x80) == drive
) && /* and it's the one we want */
279 (DRIVE_LastTask
!= GetCurrentTask())) /* and the task changed */
281 /* Perform the task-switch */
282 if (!DRIVE_Chdir( drive
, pTask
->curdir
)) DRIVE_Chdir( drive
, "\\" );
283 DRIVE_LastTask
= GetCurrentTask();
285 return DOSDrives
[drive
].dos_cwd
;
289 /***********************************************************************
292 const char * DRIVE_GetUnixCwd( int drive
)
294 TDB
*pTask
= (TDB
*)GlobalLock16( GetCurrentTask() );
295 if (!DRIVE_IsValid( drive
)) return NULL
;
297 /* Check if we need to change the directory to the new task. */
298 if (pTask
&& (pTask
->curdrive
& 0x80) && /* The task drive is valid */
299 ((pTask
->curdrive
& ~0x80) == drive
) && /* and it's the one we want */
300 (DRIVE_LastTask
!= GetCurrentTask())) /* and the task changed */
302 /* Perform the task-switch */
303 if (!DRIVE_Chdir( drive
, pTask
->curdir
)) DRIVE_Chdir( drive
, "\\" );
304 DRIVE_LastTask
= GetCurrentTask();
306 return DOSDrives
[drive
].unix_cwd
;
310 /***********************************************************************
313 const char * DRIVE_GetLabel( int drive
)
315 if (!DRIVE_IsValid( drive
)) return NULL
;
316 return DOSDrives
[drive
].label
;
320 /***********************************************************************
321 * DRIVE_GetSerialNumber
323 DWORD
DRIVE_GetSerialNumber( int drive
)
325 if (!DRIVE_IsValid( drive
)) return 0;
326 return DOSDrives
[drive
].serial
;
330 /***********************************************************************
331 * DRIVE_SetSerialNumber
333 int DRIVE_SetSerialNumber( int drive
, DWORD serial
)
335 if (!DRIVE_IsValid( drive
)) return 0;
336 DOSDrives
[drive
].serial
= serial
;
341 /***********************************************************************
344 DRIVETYPE
DRIVE_GetType( int drive
)
346 if (!DRIVE_IsValid( drive
)) return TYPE_INVALID
;
347 return DOSDrives
[drive
].type
;
351 /***********************************************************************
354 int DRIVE_Chdir( int drive
, const char *path
)
356 char buffer
[MAX_PATHNAME_LEN
];
357 const char *unix_cwd
, *dos_cwd
;
359 TDB
*pTask
= (TDB
*)GlobalLock16( GetCurrentTask() );
361 dprintf_dosfs( stddeb
, "DRIVE_Chdir(%c:,%s)\n", 'A' + drive
, path
);
362 strcpy( buffer
, "A:" );
364 lstrcpyn( buffer
+ 2, path
, sizeof(buffer
) - 2 );
366 if (!(unix_cwd
= DOSFS_GetUnixFileName( buffer
, TRUE
))) return 0;
367 if (!FILE_Stat( unix_cwd
, &attr
, NULL
, NULL
, NULL
)) return 0;
368 if (!(attr
& FA_DIRECTORY
))
370 DOS_ERROR( ER_FileNotFound
, EC_NotFound
, SA_Abort
, EL_Disk
);
373 unix_cwd
+= strlen( DOSDrives
[drive
].root
);
374 while (*unix_cwd
== '/') unix_cwd
++;
376 lstrcpyn( buffer
+ 3, unix_cwd
, sizeof(buffer
) - 3 );
377 if (!(dos_cwd
= DOSFS_GetDosTrueName( buffer
, TRUE
))) return 0;
379 dprintf_dosfs( stddeb
, "DRIVE_Chdir(%c:): unix_cwd=%s dos_cwd=%s\n",
380 'A' + drive
, unix_cwd
, dos_cwd
+ 3 );
382 free( DOSDrives
[drive
].dos_cwd
);
383 free( DOSDrives
[drive
].unix_cwd
);
384 DOSDrives
[drive
].dos_cwd
= xstrdup( dos_cwd
+ 3 );
385 DOSDrives
[drive
].unix_cwd
= xstrdup( unix_cwd
);
387 if (pTask
&& (pTask
->curdrive
& 0x80) &&
388 ((pTask
->curdrive
& ~0x80) == drive
))
390 lstrcpyn( pTask
->curdir
, dos_cwd
+ 2, sizeof(pTask
->curdir
) );
391 DRIVE_LastTask
= GetCurrentTask();
397 /***********************************************************************
400 int DRIVE_Disable( int drive
)
402 if ((drive
< 0) || (drive
>= MAX_DOS_DRIVES
) || !DOSDrives
[drive
].root
)
404 DOS_ERROR( ER_InvalidDrive
, EC_MediaError
, SA_Abort
, EL_Disk
);
407 DOSDrives
[drive
].disabled
= 1;
412 /***********************************************************************
415 int DRIVE_Enable( int drive
)
417 if ((drive
< 0) || (drive
>= MAX_DOS_DRIVES
) || !DOSDrives
[drive
].root
)
419 DOS_ERROR( ER_InvalidDrive
, EC_MediaError
, SA_Abort
, EL_Disk
);
422 DOSDrives
[drive
].disabled
= 0;
427 /***********************************************************************
430 int DRIVE_GetFreeSpace( int drive
, DWORD
*size
, DWORD
*available
)
434 if (!DRIVE_IsValid(drive
))
436 DOS_ERROR( ER_InvalidDrive
, EC_MediaError
, SA_Abort
, EL_Disk
);
440 #if defined(__svr4__) || defined(_SCO_DS)
441 if (statfs( DOSDrives
[drive
].root
, &info
, 0, 0) < 0)
443 if (statfs( DOSDrives
[drive
].root
, &info
) < 0)
447 fprintf(stderr
,"dosfs: cannot do statfs(%s)\n", DOSDrives
[drive
].root
);
451 *size
= info
.f_bsize
* info
.f_blocks
;
452 #if defined(__svr4__) || defined(_SCO_DS)
453 *available
= info
.f_bfree
* info
.f_bsize
;
455 *available
= info
.f_bavail
* info
.f_bsize
;
461 /***********************************************************************
462 * GetDriveType (KERNEL.136)
464 WORD
GetDriveType( INT drive
)
466 dprintf_dosfs( stddeb
, "GetDriveType(%c:)\n", 'A' + drive
);
467 switch(DRIVE_GetType(drive
))
469 case TYPE_FLOPPY
: return DRIVE_REMOVABLE
;
470 case TYPE_HD
: return DRIVE_FIXED
;
471 case TYPE_CDROM
: return DRIVE_REMOVABLE
;
472 case TYPE_NETWORK
: return DRIVE_REMOTE
;
474 default: return DRIVE_CANNOTDETERMINE
;
479 /***********************************************************************
480 * GetCurrentDirectory (KERNEL.411)
482 UINT32
GetCurrentDirectory( UINT32 buflen
, LPSTR buf
)
484 const char *s
= DRIVE_GetDosCwd( DRIVE_GetCurrentDrive() );
490 lstrcpyn( buf
, s
, buflen
);
491 return strlen(s
); /* yes */
495 /***********************************************************************
496 * SetCurrentDirectory (KERNEL.412)
498 BOOL32
SetCurrentDirectory( LPCSTR dir
)
500 return DRIVE_Chdir( DRIVE_GetCurrentDrive(), dir
);