From 7e3d265469996efc7e720685be9b2c524eb7434b Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Thu, 18 Jun 2020 14:45:32 +0200 Subject: [PATCH] ntdll: Move the volume information functions to the Unix library. Signed-off-by: Alexandre Julliard --- dlls/ntdll/file.c | 610 +-------------------------------------- dlls/ntdll/ntdll_misc.h | 1 - dlls/ntdll/unix/file.c | 442 +++++++++++++++++++++++++++- dlls/ntdll/unix/loader.c | 2 + dlls/ntdll/unixlib.h | 7 +- 5 files changed, 453 insertions(+), 609 deletions(-) diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c index 0eaf4a06b52..fb70d8995a1 100644 --- a/dlls/ntdll/file.c +++ b/dlls/ntdll/file.c @@ -112,9 +112,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(ntdll); -#define FILE_WRITE_TO_END_OF_FILE ((LONGLONG)-1) -#define FILE_USE_FILE_POINTER_POSITION ((LONGLONG)-2) - /************************************************************************** * NtOpenFile [NTDLL.@] @@ -257,56 +254,6 @@ static async_data_t server_async( HANDLE handle, struct async_fileio *user, HAND return async; } -/*********************************************************************** - * FILE_GetNtStatus(void) - * - * Retrieve the Nt Status code from errno. - * Try to be consistent with FILE_SetDosError(). - */ -NTSTATUS FILE_GetNtStatus(void) -{ - int err = errno; - - TRACE( "errno = %d\n", errno ); - switch (err) - { - 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: - case EACCES: return STATUS_ACCESS_DENIED; - case ENOTDIR: return STATUS_OBJECT_PATH_NOT_FOUND; - case ENOENT: return STATUS_OBJECT_NAME_NOT_FOUND; - case EISDIR: return STATUS_FILE_IS_A_DIRECTORY; - case EMFILE: - case ENFILE: return STATUS_TOO_MANY_OPENED_FILES; - case EINVAL: return STATUS_INVALID_PARAMETER; - case ENOTEMPTY: return STATUS_DIRECTORY_NOT_EMPTY; - case EPIPE: return STATUS_PIPE_DISCONNECTED; - case EIO: return STATUS_DEVICE_NOT_READY; -#ifdef ENOMEDIUM - case ENOMEDIUM: return STATUS_NO_MEDIA_IN_DEVICE; -#endif - case ENXIO: return STATUS_NO_SUCH_DEVICE; - case ENOTTY: - case EOPNOTSUPP:return STATUS_NOT_SUPPORTED; - case ECONNRESET:return STATUS_PIPE_DISCONNECTED; - case EFAULT: return STATUS_ACCESS_VIOLATION; - case ESPIPE: return STATUS_ILLEGAL_FUNCTION; - case ELOOP: return STATUS_REPARSE_POINT_NOT_RESOLVED; -#ifdef ETIME /* Missing on FreeBSD */ - case ETIME: return STATUS_IO_TIMEOUT; -#endif - case ENOEXEC: /* ?? */ - case EEXIST: /* ?? */ - default: - FIXME( "Converting errno %d to STATUS_UNSUCCESSFUL\n", err ); - return STATUS_UNSUCCESSFUL; - } -} - /****************************************************************************** * NtReadFile [NTDLL.@] @@ -599,30 +546,11 @@ NTSTATUS WINAPI NtNotifyChangeDirectoryFile( HANDLE handle, HANDLE event, PIO_AP /****************************************************************************** * NtSetVolumeInformationFile [NTDLL.@] * ZwSetVolumeInformationFile [NTDLL.@] - * - * Set volume information for an open file handle. - * - * PARAMS - * FileHandle [I] Handle returned from ZwOpenFile() or ZwCreateFile() - * IoStatusBlock [O] Receives information about the operation on return - * FsInformation [I] Source for volume information - * Length [I] Size of FsInformation - * FsInformationClass [I] Type of volume information to set - * - * RETURNS - * Success: 0. IoStatusBlock is updated. - * Failure: An NTSTATUS error code describing the error. */ -NTSTATUS WINAPI NtSetVolumeInformationFile( - IN HANDLE FileHandle, - PIO_STATUS_BLOCK IoStatusBlock, - PVOID FsInformation, - ULONG Length, - FS_INFORMATION_CLASS FsInformationClass) +NTSTATUS WINAPI NtSetVolumeInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, void *info, + ULONG length, FS_INFORMATION_CLASS class ) { - FIXME("(%p,%p,%p,0x%08x,0x%08x) stub\n", - FileHandle,IoStatusBlock,FsInformation,Length,FsInformationClass); - return 0; + return unix_funcs->NtSetVolumeInformationFile( handle, io, info, length, class ); } NTSTATUS server_get_unix_name( HANDLE handle, ANSI_STRING *unix_name ) @@ -659,126 +587,6 @@ NTSTATUS server_get_unix_name( HANDLE handle, ANSI_STRING *unix_name ) return ret; } -/* Find a DOS device which can act as the root of "path". - * Similar to find_drive_root(), but returns -1 instead of crossing volumes. */ -static int find_dos_device( const char *path ) -{ - int len = strlen(path); - int drive; - char *buffer; - struct stat st; - struct drive_info info[MAX_DOS_DRIVES]; - dev_t dev_id; - - if (!DIR_get_drives_info( info )) return -1; - - if (stat( path, &st ) < 0) return -1; - dev_id = st.st_dev; - - /* strip off trailing slashes */ - while (len > 1 && path[len - 1] == '/') len--; - - /* make a copy of the path */ - if (!(buffer = RtlAllocateHeap( GetProcessHeap(), 0, len + 1 ))) return -1; - memcpy( buffer, path, len ); - buffer[len] = 0; - - for (;;) - { - if (!stat( buffer, &st ) && S_ISDIR( st.st_mode )) - { - if (st.st_dev != dev_id) break; - - for (drive = 0; drive < MAX_DOS_DRIVES; drive++) - { - if ((info[drive].dev == st.st_dev) && (info[drive].ino == st.st_ino)) - { - if (len == 1) len = 0; /* preserve root slash in returned path */ - TRACE( "%s -> drive %c:, root=%s, name=%s\n", - debugstr_a(path), 'A' + drive, debugstr_a(buffer), debugstr_a(path + len)); - RtlFreeHeap( GetProcessHeap(), 0, buffer ); - return drive; - } - } - } - if (len <= 1) break; /* reached root */ - while (path[len - 1] != '/') len--; - while (path[len - 1] == '/') len--; - buffer[len] = 0; - } - RtlFreeHeap( GetProcessHeap(), 0, buffer ); - return -1; -} - -static struct mountmgr_unix_drive *get_mountmgr_fs_info( HANDLE handle, int fd ) -{ - struct mountmgr_unix_drive *drive; - OBJECT_ATTRIBUTES attr; - UNICODE_STRING string; - ANSI_STRING unix_name; - IO_STATUS_BLOCK io; - HANDLE mountmgr; - NTSTATUS status; - int letter; - - if (server_get_unix_name( handle, &unix_name )) - return NULL; - - letter = find_dos_device( unix_name.Buffer ); - RtlFreeAnsiString( &unix_name ); - - if (!(drive = RtlAllocateHeap( GetProcessHeap(), 0, 1024 ))) - return NULL; - - if (letter == -1) - { - struct stat st; - - if (fstat( fd, &st ) == -1) - { - RtlFreeHeap( GetProcessHeap(), 0, drive ); - return NULL; - } - - drive->unix_dev = st.st_dev; - drive->letter = 0; - } - else - drive->letter = 'a' + letter; - - RtlInitUnicodeString( &string, MOUNTMGR_DEVICE_NAME ); - InitializeObjectAttributes( &attr, &string, 0, NULL, NULL ); - if (NtOpenFile( &mountmgr, GENERIC_READ | SYNCHRONIZE, &attr, &io, - FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT )) - { - RtlFreeHeap( GetProcessHeap(), 0, drive ); - return NULL; - } - - status = NtDeviceIoControlFile( mountmgr, NULL, NULL, NULL, &io, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE, - drive, sizeof(*drive), drive, 1024 ); - if (status == STATUS_BUFFER_OVERFLOW) - { - if (!(drive = RtlReAllocateHeap( GetProcessHeap(), 0, drive, drive->size ))) - { - RtlFreeHeap( GetProcessHeap(), 0, drive ); - NtClose( mountmgr ); - return NULL; - } - status = NtDeviceIoControlFile( mountmgr, NULL, NULL, NULL, &io, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE, - drive, sizeof(*drive), drive, drive->size ); - } - NtClose( mountmgr ); - - if (status) - { - WARN("failed to retrieve filesystem type from mountmgr, status %#x\n", status); - RtlFreeHeap( GetProcessHeap(), 0, drive ); - return NULL; - } - - return drive; -} /****************************************************************************** * NtQueryInformationFile [NTDLL.@] @@ -847,184 +655,6 @@ NTSTATUS WINAPI NtQueryAttributesFile( const OBJECT_ATTRIBUTES *attr, FILE_BASIC } -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__) -/* helper for FILE_GetDeviceInfo to hide some platform differences in fstatfs */ -static inline void get_device_info_fstatfs( FILE_FS_DEVICE_INFORMATION *info, const char *fstypename, - unsigned int flags ) -{ - if (!strcmp("cd9660", fstypename) || !strcmp("udf", fstypename)) - { - info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM; - /* Don't assume read-only, let the mount options set it below */ - info->Characteristics |= FILE_REMOVABLE_MEDIA; - } - else if (!strcmp("nfs", fstypename) || !strcmp("nwfs", fstypename) || - !strcmp("smbfs", fstypename) || !strcmp("afpfs", fstypename)) - { - info->DeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM; - info->Characteristics |= FILE_REMOTE_DEVICE; - } - else if (!strcmp("procfs", fstypename)) - info->DeviceType = FILE_DEVICE_VIRTUAL_DISK; - else - info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM; - - if (flags & MNT_RDONLY) - info->Characteristics |= FILE_READ_ONLY_DEVICE; - - if (!(flags & MNT_LOCAL)) - { - info->DeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM; - info->Characteristics |= FILE_REMOTE_DEVICE; - } -} -#endif - -static inline BOOL is_device_placeholder( int fd ) -{ - static const char wine_placeholder[] = "Wine device placeholder"; - char buffer[sizeof(wine_placeholder)-1]; - - if (pread( fd, buffer, sizeof(wine_placeholder) - 1, 0 ) != sizeof(wine_placeholder) - 1) - return FALSE; - return !memcmp( buffer, wine_placeholder, sizeof(wine_placeholder) - 1 ); -} - -/****************************************************************************** - * get_device_info - * - * Implementation of the FileFsDeviceInformation query for NtQueryVolumeInformationFile. - */ -static NTSTATUS get_device_info( int fd, FILE_FS_DEVICE_INFORMATION *info ) -{ - struct stat st; - - info->Characteristics = 0; - if (fstat( fd, &st ) < 0) return FILE_GetNtStatus(); - if (S_ISCHR( st.st_mode )) - { - info->DeviceType = FILE_DEVICE_UNKNOWN; -#ifdef linux - switch(major(st.st_rdev)) - { - case MEM_MAJOR: - info->DeviceType = FILE_DEVICE_NULL; - break; - case TTY_MAJOR: - info->DeviceType = FILE_DEVICE_SERIAL_PORT; - break; - case LP_MAJOR: - info->DeviceType = FILE_DEVICE_PARALLEL_PORT; - break; - case SCSI_TAPE_MAJOR: - info->DeviceType = FILE_DEVICE_TAPE; - break; - } -#endif - } - else if (S_ISBLK( st.st_mode )) - { - info->DeviceType = FILE_DEVICE_DISK; - } - else if (S_ISFIFO( st.st_mode ) || S_ISSOCK( st.st_mode )) - { - info->DeviceType = FILE_DEVICE_NAMED_PIPE; - } - else if (is_device_placeholder( fd )) - { - info->DeviceType = FILE_DEVICE_DISK; - } - else /* regular file or directory */ - { -#if defined(linux) && defined(HAVE_FSTATFS) - struct statfs stfs; - - /* check for floppy disk */ - if (major(st.st_dev) == FLOPPY_MAJOR) - info->Characteristics |= FILE_REMOVABLE_MEDIA; - - if (fstatfs( fd, &stfs ) < 0) stfs.f_type = 0; - switch (stfs.f_type) - { - case 0x9660: /* iso9660 */ - case 0x9fa1: /* supermount */ - case 0x15013346: /* udf */ - info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM; - info->Characteristics |= FILE_REMOVABLE_MEDIA|FILE_READ_ONLY_DEVICE; - break; - case 0x6969: /* nfs */ - case 0xff534d42: /* cifs */ - case 0xfe534d42: /* smb2 */ - case 0x517b: /* smbfs */ - case 0x564c: /* ncpfs */ - info->DeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM; - info->Characteristics |= FILE_REMOTE_DEVICE; - break; - case 0x01021994: /* tmpfs */ - case 0x28cd3d45: /* cramfs */ - case 0x1373: /* devfs */ - case 0x9fa0: /* procfs */ - info->DeviceType = FILE_DEVICE_VIRTUAL_DISK; - break; - default: - info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM; - break; - } -#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__) - struct statfs stfs; - - if (fstatfs( fd, &stfs ) < 0) - info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM; - else - get_device_info_fstatfs( info, stfs.f_fstypename, stfs.f_flags ); -#elif defined(__NetBSD__) - struct statvfs stfs; - - if (fstatvfs( fd, &stfs) < 0) - info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM; - else - get_device_info_fstatfs( info, stfs.f_fstypename, stfs.f_flag ); -#elif defined(sun) - /* Use dkio to work out device types */ - { -# include -# include - struct dk_cinfo dkinf; - int retval = ioctl(fd, DKIOCINFO, &dkinf); - if(retval==-1){ - WARN("Unable to get disk device type information - assuming a disk like device\n"); - info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM; - } - switch (dkinf.dki_ctype) - { - case DKC_CDROM: - info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM; - info->Characteristics |= FILE_REMOVABLE_MEDIA|FILE_READ_ONLY_DEVICE; - break; - case DKC_NCRFLOPPY: - case DKC_SMSFLOPPY: - case DKC_INTEL82072: - case DKC_INTEL82077: - info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM; - info->Characteristics |= FILE_REMOVABLE_MEDIA; - break; - case DKC_MD: - info->DeviceType = FILE_DEVICE_VIRTUAL_DISK; - break; - default: - info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM; - } - } -#else - static int warned; - if (!warned++) FIXME( "device info not properly supported on this platform\n" ); - info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM; -#endif - info->Characteristics |= FILE_DEVICE_IS_MOUNTED; - } - return STATUS_SUCCESS; -} - /****************************************************************************** * NtQueryVolumeInformationFile [NTDLL.@] * ZwQueryVolumeInformationFile [NTDLL.@] @@ -1046,239 +676,7 @@ NTSTATUS WINAPI NtQueryVolumeInformationFile( HANDLE handle, PIO_STATUS_BLOCK io PVOID buffer, ULONG length, FS_INFORMATION_CLASS info_class ) { - int fd, needs_close; - struct stat st; - - io->u.Status = unix_funcs->server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL ); - if (io->u.Status == STATUS_BAD_DEVICE_TYPE) - { - SERVER_START_REQ( get_volume_info ) - { - req->handle = wine_server_obj_handle( handle ); - req->info_class = info_class; - wine_server_set_reply( req, buffer, length ); - io->u.Status = wine_server_call( req ); - if (!io->u.Status) io->Information = wine_server_reply_size( reply ); - } - SERVER_END_REQ; - return io->u.Status; - } - else if (io->u.Status) return io->u.Status; - - io->u.Status = STATUS_NOT_IMPLEMENTED; - io->Information = 0; - - switch( info_class ) - { - case FileFsLabelInformation: - FIXME( "%p: label info not supported\n", handle ); - break; - case FileFsSizeInformation: - if (length < sizeof(FILE_FS_SIZE_INFORMATION)) - io->u.Status = STATUS_BUFFER_TOO_SMALL; - else - { - FILE_FS_SIZE_INFORMATION *info = buffer; - - if (fstat( fd, &st ) < 0) - { - io->u.Status = FILE_GetNtStatus(); - break; - } - if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) - { - io->u.Status = STATUS_INVALID_DEVICE_REQUEST; - } - else - { - ULONGLONG bsize; - /* Linux's fstatvfs is buggy */ -#if !defined(linux) || !defined(HAVE_FSTATFS) - struct statvfs stfs; - - if (fstatvfs( fd, &stfs ) < 0) - { - io->u.Status = FILE_GetNtStatus(); - break; - } - bsize = stfs.f_frsize; -#else - struct statfs stfs; - if (fstatfs( fd, &stfs ) < 0) - { - io->u.Status = FILE_GetNtStatus(); - break; - } - bsize = stfs.f_bsize; -#endif - if (bsize == 2048) /* assume CD-ROM */ - { - info->BytesPerSector = 2048; - info->SectorsPerAllocationUnit = 1; - } - else - { - info->BytesPerSector = 512; - info->SectorsPerAllocationUnit = 8; - } - info->TotalAllocationUnits.QuadPart = bsize * stfs.f_blocks / (info->BytesPerSector * info->SectorsPerAllocationUnit); - info->AvailableAllocationUnits.QuadPart = bsize * stfs.f_bavail / (info->BytesPerSector * info->SectorsPerAllocationUnit); - io->Information = sizeof(*info); - io->u.Status = STATUS_SUCCESS; - } - } - break; - case FileFsDeviceInformation: - if (length < sizeof(FILE_FS_DEVICE_INFORMATION)) - io->u.Status = STATUS_BUFFER_TOO_SMALL; - else - { - FILE_FS_DEVICE_INFORMATION *info = buffer; - - if ((io->u.Status = get_device_info( fd, info )) == STATUS_SUCCESS) - io->Information = sizeof(*info); - } - break; - case FileFsAttributeInformation: - { - static const WCHAR fatW[] = {'F','A','T'}; - static const WCHAR fat32W[] = {'F','A','T','3','2'}; - static const WCHAR ntfsW[] = {'N','T','F','S'}; - static const WCHAR cdfsW[] = {'C','D','F','S'}; - static const WCHAR udfW[] = {'U','D','F'}; - - FILE_FS_ATTRIBUTE_INFORMATION *info = buffer; - struct mountmgr_unix_drive *drive; - enum mountmgr_fs_type fs_type = MOUNTMGR_FS_TYPE_NTFS; - - if (length < sizeof(FILE_FS_ATTRIBUTE_INFORMATION)) - { - io->u.Status = STATUS_INFO_LENGTH_MISMATCH; - break; - } - - if ((drive = get_mountmgr_fs_info( handle, fd ))) - { - fs_type = drive->fs_type; - RtlFreeHeap( GetProcessHeap(), 0, drive ); - } - else - { - struct statfs stfs; - - if (!fstatfs( fd, &stfs )) - { -#if defined(linux) && defined(HAVE_FSTATFS) - switch (stfs.f_type) - { - case 0x9660: - fs_type = MOUNTMGR_FS_TYPE_ISO9660; - break; - case 0x15013346: - fs_type = MOUNTMGR_FS_TYPE_UDF; - break; - case 0x4d44: - fs_type = MOUNTMGR_FS_TYPE_FAT32; - break; - } -#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__) - if (!strcmp( stfs.f_fstypename, "cd9660" )) - fs_type = MOUNTMGR_FS_TYPE_ISO9660; - else if (!strcmp( stfs.f_fstypename, "udf" )) - fs_type = MOUNTMGR_FS_TYPE_UDF; - else if (!strcmp( stfs.f_fstypename, "msdos" )) - fs_type = MOUNTMGR_FS_TYPE_FAT32; -#endif - } - } - - switch (fs_type) - { - case MOUNTMGR_FS_TYPE_ISO9660: - info->FileSystemAttributes = FILE_READ_ONLY_VOLUME; - info->MaximumComponentNameLength = 221; - info->FileSystemNameLength = min( sizeof(cdfsW), length - offsetof( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ) ); - memcpy(info->FileSystemName, cdfsW, info->FileSystemNameLength); - break; - case MOUNTMGR_FS_TYPE_UDF: - info->FileSystemAttributes = FILE_READ_ONLY_VOLUME | FILE_UNICODE_ON_DISK | FILE_CASE_SENSITIVE_SEARCH; - info->MaximumComponentNameLength = 255; - info->FileSystemNameLength = min( sizeof(udfW), length - offsetof( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ) ); - memcpy(info->FileSystemName, udfW, info->FileSystemNameLength); - break; - case MOUNTMGR_FS_TYPE_FAT: - info->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES; /* FIXME */ - info->MaximumComponentNameLength = 255; - info->FileSystemNameLength = min( sizeof(fatW), length - offsetof( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ) ); - memcpy(info->FileSystemName, fatW, info->FileSystemNameLength); - break; - case MOUNTMGR_FS_TYPE_FAT32: - info->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES; /* FIXME */ - info->MaximumComponentNameLength = 255; - info->FileSystemNameLength = min( sizeof(fat32W), length - offsetof( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ) ); - memcpy(info->FileSystemName, fat32W, info->FileSystemNameLength); - break; - default: - info->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES | FILE_PERSISTENT_ACLS; - info->MaximumComponentNameLength = 255; - info->FileSystemNameLength = min( sizeof(ntfsW), length - offsetof( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ) ); - memcpy(info->FileSystemName, ntfsW, info->FileSystemNameLength); - break; - } - - io->Information = offsetof( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ) + info->FileSystemNameLength; - io->u.Status = STATUS_SUCCESS; - break; - } - case FileFsVolumeInformation: - { - FILE_FS_VOLUME_INFORMATION *info = buffer; - struct mountmgr_unix_drive *drive; - const WCHAR *label; - - if (length < sizeof(FILE_FS_VOLUME_INFORMATION)) - { - io->u.Status = STATUS_INFO_LENGTH_MISMATCH; - break; - } - - if (!(drive = get_mountmgr_fs_info( handle, fd ))) - { - io->u.Status = STATUS_NOT_IMPLEMENTED; - break; - } - - label = (WCHAR *)((char *)drive + drive->label_offset); - info->VolumeCreationTime.QuadPart = 0; /* FIXME */ - info->VolumeSerialNumber = drive->serial; - info->VolumeLabelLength = min( wcslen( label ) * sizeof(WCHAR), - length - offsetof( FILE_FS_VOLUME_INFORMATION, VolumeLabel ) ); - info->SupportsObjects = (drive->fs_type == MOUNTMGR_FS_TYPE_NTFS); - memcpy( info->VolumeLabel, label, info->VolumeLabelLength ); - RtlFreeHeap( GetProcessHeap(), 0, drive ); - - io->Information = offsetof( FILE_FS_VOLUME_INFORMATION, VolumeLabel ) + info->VolumeLabelLength; - io->u.Status = STATUS_SUCCESS; - break; - } - case FileFsControlInformation: - FIXME( "%p: control info not supported\n", handle ); - break; - case FileFsFullSizeInformation: - FIXME( "%p: full size info not supported\n", handle ); - break; - case FileFsObjectIdInformation: - FIXME( "%p: object id info not supported\n", handle ); - break; - case FileFsMaximumInformation: - FIXME( "%p: maximum info not supported\n", handle ); - break; - default: - io->u.Status = STATUS_INVALID_PARAMETER; - break; - } - if (needs_close) close( fd ); - return io->u.Status; + return unix_funcs->NtQueryVolumeInformationFile( handle, io, buffer, length, info_class ); } diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h index ec986df451a..47800db41b1 100644 --- a/dlls/ntdll/ntdll_misc.h +++ b/dlls/ntdll/ntdll_misc.h @@ -112,7 +112,6 @@ extern const WCHAR syswow64_dir[] DECLSPEC_HIDDEN; extern const struct unix_funcs *unix_funcs DECLSPEC_HIDDEN; /* file I/O */ -extern NTSTATUS FILE_GetNtStatus(void) DECLSPEC_HIDDEN; extern NTSTATUS server_get_unix_name( HANDLE handle, ANSI_STRING *unix_name ) DECLSPEC_HIDDEN; extern void init_directories(void) DECLSPEC_HIDDEN; extern unsigned int DIR_get_drives_info( struct drive_info info[MAX_DOS_DRIVES] ) DECLSPEC_HIDDEN; diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index bd15df9f968..23508864514 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -46,6 +46,9 @@ #ifdef HAVE_SYS_STAT_H # include #endif +#ifdef HAVE_SYS_STATVFS_H +# include +#endif #ifdef HAVE_SYS_SYSCALL_H # include #endif @@ -1610,7 +1613,7 @@ static NTSTATUS set_file_times( int fd, const LARGE_INTEGER *mtime, const LARGE_ #ifdef HAVE_FUTIMES if (futimes( fd, tv ) == -1) status = errno_to_status( errno ); #elif defined(HAVE_FUTIMESAT) - if (futimesat( fd, NULL, tv ) == -1) status = FILE_GetNtStatus(); + if (futimesat( fd, NULL, tv ) == -1) status = errno_to_status( errno ); #endif #else /* HAVE_FUTIMES || HAVE_FUTIMESAT */ @@ -5725,3 +5728,440 @@ NTSTATUS WINAPI NtFlushBuffersFile( HANDLE handle, IO_STATUS_BLOCK *io ) if (needs_close) close( fd ); return ret; } + + +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__) +/* helper for FILE_GetDeviceInfo to hide some platform differences in fstatfs */ +static inline void get_device_info_fstatfs( FILE_FS_DEVICE_INFORMATION *info, const char *fstypename, + unsigned int flags ) +{ + if (!strcmp("cd9660", fstypename) || !strcmp("udf", fstypename)) + { + info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM; + /* Don't assume read-only, let the mount options set it below */ + info->Characteristics |= FILE_REMOVABLE_MEDIA; + } + else if (!strcmp("nfs", fstypename) || !strcmp("nwfs", fstypename) || + !strcmp("smbfs", fstypename) || !strcmp("afpfs", fstypename)) + { + info->DeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM; + info->Characteristics |= FILE_REMOTE_DEVICE; + } + else if (!strcmp("procfs", fstypename)) + info->DeviceType = FILE_DEVICE_VIRTUAL_DISK; + else + info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM; + + if (flags & MNT_RDONLY) + info->Characteristics |= FILE_READ_ONLY_DEVICE; + + if (!(flags & MNT_LOCAL)) + { + info->DeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM; + info->Characteristics |= FILE_REMOTE_DEVICE; + } +} +#endif + +static inline BOOL is_device_placeholder( int fd ) +{ + static const char wine_placeholder[] = "Wine device placeholder"; + char buffer[sizeof(wine_placeholder)-1]; + + if (pread( fd, buffer, sizeof(wine_placeholder) - 1, 0 ) != sizeof(wine_placeholder) - 1) + return FALSE; + return !memcmp( buffer, wine_placeholder, sizeof(wine_placeholder) - 1 ); +} + +static NTSTATUS get_device_info( int fd, FILE_FS_DEVICE_INFORMATION *info ) +{ + struct stat st; + + info->Characteristics = 0; + if (fstat( fd, &st ) < 0) return errno_to_status( errno ); + if (S_ISCHR( st.st_mode )) + { + info->DeviceType = FILE_DEVICE_UNKNOWN; +#ifdef linux + switch(major(st.st_rdev)) + { + case MEM_MAJOR: + info->DeviceType = FILE_DEVICE_NULL; + break; + case TTY_MAJOR: + info->DeviceType = FILE_DEVICE_SERIAL_PORT; + break; + case LP_MAJOR: + info->DeviceType = FILE_DEVICE_PARALLEL_PORT; + break; + case SCSI_TAPE_MAJOR: + info->DeviceType = FILE_DEVICE_TAPE; + break; + } +#endif + } + else if (S_ISBLK( st.st_mode )) + { + info->DeviceType = FILE_DEVICE_DISK; + } + else if (S_ISFIFO( st.st_mode ) || S_ISSOCK( st.st_mode )) + { + info->DeviceType = FILE_DEVICE_NAMED_PIPE; + } + else if (is_device_placeholder( fd )) + { + info->DeviceType = FILE_DEVICE_DISK; + } + else /* regular file or directory */ + { +#if defined(linux) && defined(HAVE_FSTATFS) + struct statfs stfs; + + /* check for floppy disk */ + if (major(st.st_dev) == FLOPPY_MAJOR) + info->Characteristics |= FILE_REMOVABLE_MEDIA; + + if (fstatfs( fd, &stfs ) < 0) stfs.f_type = 0; + switch (stfs.f_type) + { + case 0x9660: /* iso9660 */ + case 0x9fa1: /* supermount */ + case 0x15013346: /* udf */ + info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM; + info->Characteristics |= FILE_REMOVABLE_MEDIA|FILE_READ_ONLY_DEVICE; + break; + case 0x6969: /* nfs */ + case 0xff534d42: /* cifs */ + case 0xfe534d42: /* smb2 */ + case 0x517b: /* smbfs */ + case 0x564c: /* ncpfs */ + info->DeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM; + info->Characteristics |= FILE_REMOTE_DEVICE; + break; + case 0x01021994: /* tmpfs */ + case 0x28cd3d45: /* cramfs */ + case 0x1373: /* devfs */ + case 0x9fa0: /* procfs */ + info->DeviceType = FILE_DEVICE_VIRTUAL_DISK; + break; + default: + info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM; + break; + } +#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__) + struct statfs stfs; + + if (fstatfs( fd, &stfs ) < 0) + info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM; + else + get_device_info_fstatfs( info, stfs.f_fstypename, stfs.f_flags ); +#elif defined(__NetBSD__) + struct statvfs stfs; + + if (fstatvfs( fd, &stfs) < 0) + info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM; + else + get_device_info_fstatfs( info, stfs.f_fstypename, stfs.f_flag ); +#elif defined(sun) + /* Use dkio to work out device types */ + { +# include +# include + struct dk_cinfo dkinf; + int retval = ioctl(fd, DKIOCINFO, &dkinf); + if(retval==-1){ + WARN("Unable to get disk device type information - assuming a disk like device\n"); + info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM; + } + switch (dkinf.dki_ctype) + { + case DKC_CDROM: + info->DeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM; + info->Characteristics |= FILE_REMOVABLE_MEDIA|FILE_READ_ONLY_DEVICE; + break; + case DKC_NCRFLOPPY: + case DKC_SMSFLOPPY: + case DKC_INTEL82072: + case DKC_INTEL82077: + info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM; + info->Characteristics |= FILE_REMOVABLE_MEDIA; + break; + case DKC_MD: + info->DeviceType = FILE_DEVICE_VIRTUAL_DISK; + break; + default: + info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM; + } + } +#else + static int warned; + if (!warned++) FIXME( "device info not properly supported on this platform\n" ); + info->DeviceType = FILE_DEVICE_DISK_FILE_SYSTEM; +#endif + info->Characteristics |= FILE_DEVICE_IS_MOUNTED; + } + return STATUS_SUCCESS; +} + + +/****************************************************************************** + * NtQueryVolumeInformationFile (NTDLL.@) + */ +NTSTATUS WINAPI NtQueryVolumeInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, + void *buffer, ULONG length, + FS_INFORMATION_CLASS info_class ) +{ + int fd, needs_close; + struct stat st; + + io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL ); + if (io->u.Status == STATUS_BAD_DEVICE_TYPE) + { + SERVER_START_REQ( get_volume_info ) + { + req->handle = wine_server_obj_handle( handle ); + req->info_class = info_class; + wine_server_set_reply( req, buffer, length ); + io->u.Status = wine_server_call( req ); + if (!io->u.Status) io->Information = wine_server_reply_size( reply ); + } + SERVER_END_REQ; + return io->u.Status; + } + else if (io->u.Status) return io->u.Status; + + io->u.Status = STATUS_NOT_IMPLEMENTED; + io->Information = 0; + + switch( info_class ) + { + case FileFsLabelInformation: + FIXME( "%p: label info not supported\n", handle ); + break; + + case FileFsSizeInformation: + if (length < sizeof(FILE_FS_SIZE_INFORMATION)) + io->u.Status = STATUS_BUFFER_TOO_SMALL; + else + { + FILE_FS_SIZE_INFORMATION *info = buffer; + + if (fstat( fd, &st ) < 0) + { + io->u.Status = errno_to_status( errno ); + break; + } + if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) + { + io->u.Status = STATUS_INVALID_DEVICE_REQUEST; + } + else + { + ULONGLONG bsize; + /* Linux's fstatvfs is buggy */ +#if !defined(linux) || !defined(HAVE_FSTATFS) + struct statvfs stfs; + + if (fstatvfs( fd, &stfs ) < 0) + { + io->u.Status = errno_to_status( errno ); + break; + } + bsize = stfs.f_frsize; +#else + struct statfs stfs; + if (fstatfs( fd, &stfs ) < 0) + { + io->u.Status = errno_to_status( errno ); + break; + } + bsize = stfs.f_bsize; +#endif + if (bsize == 2048) /* assume CD-ROM */ + { + info->BytesPerSector = 2048; + info->SectorsPerAllocationUnit = 1; + } + else + { + info->BytesPerSector = 512; + info->SectorsPerAllocationUnit = 8; + } + info->TotalAllocationUnits.QuadPart = bsize * stfs.f_blocks / (info->BytesPerSector * info->SectorsPerAllocationUnit); + info->AvailableAllocationUnits.QuadPart = bsize * stfs.f_bavail / (info->BytesPerSector * info->SectorsPerAllocationUnit); + io->Information = sizeof(*info); + io->u.Status = STATUS_SUCCESS; + } + } + break; + + case FileFsDeviceInformation: + if (length < sizeof(FILE_FS_DEVICE_INFORMATION)) + io->u.Status = STATUS_BUFFER_TOO_SMALL; + else + { + FILE_FS_DEVICE_INFORMATION *info = buffer; + + if ((io->u.Status = get_device_info( fd, info )) == STATUS_SUCCESS) + io->Information = sizeof(*info); + } + break; + + case FileFsAttributeInformation: + { + static const WCHAR fatW[] = {'F','A','T'}; + static const WCHAR fat32W[] = {'F','A','T','3','2'}; + static const WCHAR ntfsW[] = {'N','T','F','S'}; + static const WCHAR cdfsW[] = {'C','D','F','S'}; + static const WCHAR udfW[] = {'U','D','F'}; + + FILE_FS_ATTRIBUTE_INFORMATION *info = buffer; + struct mountmgr_unix_drive *drive; + enum mountmgr_fs_type fs_type = MOUNTMGR_FS_TYPE_NTFS; + + if (length < sizeof(FILE_FS_ATTRIBUTE_INFORMATION)) + { + io->u.Status = STATUS_INFO_LENGTH_MISMATCH; + break; + } + + if ((drive = get_mountmgr_fs_info( handle, fd ))) + { + fs_type = drive->fs_type; + RtlFreeHeap( GetProcessHeap(), 0, drive ); + } + else + { + struct statfs stfs; + + if (!fstatfs( fd, &stfs )) + { +#if defined(linux) && defined(HAVE_FSTATFS) + switch (stfs.f_type) + { + case 0x9660: + fs_type = MOUNTMGR_FS_TYPE_ISO9660; + break; + case 0x15013346: + fs_type = MOUNTMGR_FS_TYPE_UDF; + break; + case 0x4d44: + fs_type = MOUNTMGR_FS_TYPE_FAT32; + break; + } +#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__) + if (!strcmp( stfs.f_fstypename, "cd9660" )) + fs_type = MOUNTMGR_FS_TYPE_ISO9660; + else if (!strcmp( stfs.f_fstypename, "udf" )) + fs_type = MOUNTMGR_FS_TYPE_UDF; + else if (!strcmp( stfs.f_fstypename, "msdos" )) + fs_type = MOUNTMGR_FS_TYPE_FAT32; +#endif + } + } + + switch (fs_type) + { + case MOUNTMGR_FS_TYPE_ISO9660: + info->FileSystemAttributes = FILE_READ_ONLY_VOLUME; + info->MaximumComponentNameLength = 221; + info->FileSystemNameLength = min( sizeof(cdfsW), length - offsetof( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ) ); + memcpy(info->FileSystemName, cdfsW, info->FileSystemNameLength); + break; + case MOUNTMGR_FS_TYPE_UDF: + info->FileSystemAttributes = FILE_READ_ONLY_VOLUME | FILE_UNICODE_ON_DISK | FILE_CASE_SENSITIVE_SEARCH; + info->MaximumComponentNameLength = 255; + info->FileSystemNameLength = min( sizeof(udfW), length - offsetof( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ) ); + memcpy(info->FileSystemName, udfW, info->FileSystemNameLength); + break; + case MOUNTMGR_FS_TYPE_FAT: + info->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES; /* FIXME */ + info->MaximumComponentNameLength = 255; + info->FileSystemNameLength = min( sizeof(fatW), length - offsetof( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ) ); + memcpy(info->FileSystemName, fatW, info->FileSystemNameLength); + break; + case MOUNTMGR_FS_TYPE_FAT32: + info->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES; /* FIXME */ + info->MaximumComponentNameLength = 255; + info->FileSystemNameLength = min( sizeof(fat32W), length - offsetof( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ) ); + memcpy(info->FileSystemName, fat32W, info->FileSystemNameLength); + break; + default: + info->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES | FILE_PERSISTENT_ACLS; + info->MaximumComponentNameLength = 255; + info->FileSystemNameLength = min( sizeof(ntfsW), length - offsetof( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ) ); + memcpy(info->FileSystemName, ntfsW, info->FileSystemNameLength); + break; + } + + io->Information = offsetof( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ) + info->FileSystemNameLength; + io->u.Status = STATUS_SUCCESS; + break; + } + + case FileFsVolumeInformation: + { + FILE_FS_VOLUME_INFORMATION *info = buffer; + struct mountmgr_unix_drive *drive; + const WCHAR *label; + + if (length < sizeof(FILE_FS_VOLUME_INFORMATION)) + { + io->u.Status = STATUS_INFO_LENGTH_MISMATCH; + break; + } + + if (!(drive = get_mountmgr_fs_info( handle, fd ))) + { + io->u.Status = STATUS_NOT_IMPLEMENTED; + break; + } + + label = (WCHAR *)((char *)drive + drive->label_offset); + info->VolumeCreationTime.QuadPart = 0; /* FIXME */ + info->VolumeSerialNumber = drive->serial; + info->VolumeLabelLength = min( wcslen( label ) * sizeof(WCHAR), + length - offsetof( FILE_FS_VOLUME_INFORMATION, VolumeLabel ) ); + info->SupportsObjects = (drive->fs_type == MOUNTMGR_FS_TYPE_NTFS); + memcpy( info->VolumeLabel, label, info->VolumeLabelLength ); + RtlFreeHeap( GetProcessHeap(), 0, drive ); + + io->Information = offsetof( FILE_FS_VOLUME_INFORMATION, VolumeLabel ) + info->VolumeLabelLength; + io->u.Status = STATUS_SUCCESS; + break; + } + + case FileFsControlInformation: + FIXME( "%p: control info not supported\n", handle ); + break; + + case FileFsFullSizeInformation: + FIXME( "%p: full size info not supported\n", handle ); + break; + + case FileFsObjectIdInformation: + FIXME( "%p: object id info not supported\n", handle ); + break; + + case FileFsMaximumInformation: + FIXME( "%p: maximum info not supported\n", handle ); + break; + + default: + io->u.Status = STATUS_INVALID_PARAMETER; + break; + } + if (needs_close) close( fd ); + return io->u.Status; +} + + +/****************************************************************************** + * NtSetVolumeInformationFile (NTDLL.@) + */ +NTSTATUS WINAPI NtSetVolumeInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, void *info, + ULONG length, FS_INFORMATION_CLASS class ) +{ + FIXME( "(%p,%p,%p,0x%08x,0x%08x) stub\n", handle, io, info, length, class ); + return STATUS_SUCCESS; +} diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 4ae51cb2f49..7ee695c99af 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -942,6 +942,7 @@ static struct unix_funcs unix_funcs = NtQuerySystemTime, NtQueryTimer, NtQueryVirtualMemory, + NtQueryVolumeInformationFile, NtQueueApcThread, NtRaiseException, NtReadFile, @@ -966,6 +967,7 @@ static struct unix_funcs unix_funcs = NtSetLdtEntries, NtSetSystemTime, NtSetTimer, + NtSetVolumeInformationFile, NtSignalAndWaitForSingleObject, NtSuspendProcess, NtSuspendThread, diff --git a/dlls/ntdll/unixlib.h b/dlls/ntdll/unixlib.h index 6037b6e0e6a..8ca4eba7049 100644 --- a/dlls/ntdll/unixlib.h +++ b/dlls/ntdll/unixlib.h @@ -28,7 +28,7 @@ struct ldt_copy; struct msghdr; /* increment this when you change the function table */ -#define NTDLL_UNIXLIB_VERSION 54 +#define NTDLL_UNIXLIB_VERSION 55 struct unix_funcs { @@ -172,6 +172,9 @@ struct unix_funcs NTSTATUS (WINAPI *NtQueryVirtualMemory)( HANDLE process, LPCVOID addr, MEMORY_INFORMATION_CLASS info_class, PVOID buffer, SIZE_T len, SIZE_T *res_len ); + NTSTATUS (WINAPI *NtQueryVolumeInformationFile)( HANDLE handle, IO_STATUS_BLOCK *io, + void *buffer, ULONG length, + FS_INFORMATION_CLASS info_class ); NTSTATUS (WINAPI *NtQueueApcThread)( HANDLE handle, PNTAPCFUNC func, ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3 ); NTSTATUS (WINAPI *NtRaiseException)( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance ); @@ -214,6 +217,8 @@ struct unix_funcs NTSTATUS (WINAPI *NtSetTimer)( HANDLE handle, const LARGE_INTEGER *when, PTIMER_APC_ROUTINE callback, void *arg, BOOLEAN resume, ULONG period, BOOLEAN *state ); + NTSTATUS (WINAPI *NtSetVolumeInformationFile)( HANDLE handle, IO_STATUS_BLOCK *io, void *info, + ULONG length, FS_INFORMATION_CLASS class ); NTSTATUS (WINAPI *NtSignalAndWaitForSingleObject)( HANDLE signal, HANDLE wait, BOOLEAN alertable, const LARGE_INTEGER *timeout ); NTSTATUS (WINAPI *NtSuspendProcess)( HANDLE handle );