Added an implementation of the FSCTL_DISMOUNT_VOLUME ioctl that

attempts to unmount the Unix device.
This commit is contained in:
Alexandre Julliard 2005-10-28 16:45:24 +00:00
parent ce08973ffa
commit a2fb7c1644
3 changed files with 125 additions and 0 deletions

View File

@ -43,6 +43,9 @@
#ifdef HAVE_LINUX_IOCTL_H
#include <linux/ioctl.h>
#endif
#ifdef HAVE_LINUX_MAJOR_H
# include <linux/major.h>
#endif
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
@ -497,6 +500,70 @@ static char *get_default_drive_device( const char *root )
}
/***********************************************************************
* get_device_mount_point
*
* Return the current mount point for a device.
*/
static char *get_device_mount_point( dev_t dev )
{
char *ret = NULL;
#ifdef linux
FILE *f;
RtlEnterCriticalSection( &dir_section );
if ((f = fopen( "/etc/mtab", "r" )))
{
struct mntent *entry;
struct stat st;
char *p, *device;
while ((entry = getmntent( f )))
{
/* don't even bother stat'ing network mounts, there's no meaningful device anyway */
if (!strcmp( entry->mnt_type, "nfs" ) ||
!strcmp( entry->mnt_type, "smbfs" ) ||
!strcmp( entry->mnt_type, "ncpfs" )) continue;
if (!strcmp( entry->mnt_type, "supermount" ))
{
if ((device = strstr( entry->mnt_opts, "dev=" )))
{
device += 4;
if ((p = strchr( device, ',' ))) *p = 0;
}
}
else if (!stat( entry->mnt_fsname, &st ) && S_ISREG(st.st_mode))
{
/* if device is a regular file check for a loop mount */
if ((device = strstr( entry->mnt_opts, "loop=" )))
{
device += 5;
if ((p = strchr( device, ',' ))) *p = 0;
}
}
else device = entry->mnt_fsname;
if (device && !stat( device, &st ) && S_ISBLK(st.st_mode) && st.st_rdev == dev)
{
ret = RtlAllocateHeap( GetProcessHeap(), 0, strlen(entry->mnt_dir) + 1 );
if (ret) strcpy( ret, entry->mnt_dir );
break;
}
}
endmntent( f );
}
RtlLeaveCriticalSection( &dir_section );
#else
static int warned;
if (!warned++) FIXME( "unmounting devices not supported on this platform\n" );
#endif
return ret;
}
/***********************************************************************
* init_options
*
@ -1576,6 +1643,58 @@ BOOLEAN WINAPI RtlDoesFileExists_U(LPCWSTR file_name)
}
/***********************************************************************
* DIR_unmount_device
*
* Unmount the specified device.
*/
NTSTATUS DIR_unmount_device( HANDLE handle )
{
NTSTATUS status;
int unix_fd;
SERVER_START_REQ( unmount_device )
{
req->handle = handle;
status = wine_server_call( req );
}
SERVER_END_REQ;
if (status) return status;
if (!(status = wine_server_handle_to_fd( handle, 0, &unix_fd, NULL )))
{
struct stat st;
char *mount_point = NULL;
if (fstat( unix_fd, &st ) == -1 || !S_ISBLK(st.st_mode))
status = STATUS_INVALID_PARAMETER;
else
{
if ((mount_point = get_device_mount_point( st.st_rdev )))
{
static const char umount[] = "umount >/dev/null 2>&1 ";
char *cmd = RtlAllocateHeap( GetProcessHeap(), 0, strlen(mount_point)+sizeof(umount));
if (cmd)
{
strcpy( cmd, umount );
strcat( cmd, mount_point );
system( cmd );
RtlFreeHeap( GetProcessHeap(), 0, cmd );
#ifdef linux
/* umount will fail to release the loop device since we still have
a handle to it, so we release it here */
if (major(st.st_rdev) == LOOP_MAJOR) ioctl( unix_fd, 0x4c01 /*LOOP_CLR_FD*/, 0 );
#endif
}
RtlFreeHeap( GetProcessHeap(), 0, mount_point );
}
}
wine_server_release_fd( handle, unix_fd );
}
return status;
}
/******************************************************************************
* DIR_get_unix_cwd
*

View File

@ -328,6 +328,7 @@ NTSTATUS FILE_GetNtStatus(void)
{
case EAGAIN: return STATUS_SHARING_VIOLATION;
case EBADF: return STATUS_INVALID_HANDLE;
case EBUSY: return STATUS_DEVICE_BUSY;
case ENOSPC: return STATUS_DISK_FULL;
case EPERM:
case EROFS:
@ -911,6 +912,10 @@ NTSTATUS WINAPI NtFsControlFile(HANDLE DeviceHandle, HANDLE Event OPTIONAL, PIO_
switch(FsControlCode)
{
case FSCTL_DISMOUNT_VOLUME:
ret = DIR_unmount_device( DeviceHandle );
break;
case FSCTL_PIPE_LISTEN :
{
HANDLE internal_event;

View File

@ -84,6 +84,7 @@ extern NTSTATUS CDROM_DeviceIoControl(HANDLE hDevice,
extern NTSTATUS FILE_GetNtStatus(void);
extern NTSTATUS FILE_GetDeviceInfo( int fd, FILE_FS_DEVICE_INFORMATION *info );
extern BOOL DIR_is_hidden_file( const UNICODE_STRING *name );
extern NTSTATUS DIR_unmount_device( HANDLE handle );
extern NTSTATUS DIR_get_unix_cwd( char **cwd );
/* virtual memory */