diff --git a/dlls/kernel/tests/file.c b/dlls/kernel/tests/file.c index 88fc271099c..7ec229c3071 100644 --- a/dlls/kernel/tests/file.c +++ b/dlls/kernel/tests/file.c @@ -1059,6 +1059,22 @@ static void test_MapFile() ok( DeleteFileA( filename ), "DeleteFile failed after map\n" ); } +static void test_GetFileType(void) +{ + DWORD type; + HANDLE h = CreateFileA( filename, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( h != INVALID_HANDLE_VALUE, "open %s failed\n", filename ); + type = GetFileType(h); + ok( type == FILE_TYPE_DISK, "expected type disk got %ld\n", type ); + CloseHandle( h ); + h = CreateFileA( "nul", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0 ); + ok( h != INVALID_HANDLE_VALUE, "open nul failed\n" ); + type = GetFileType(h); + ok( type == FILE_TYPE_CHAR, "expected type char for nul got %ld\n", type ); + CloseHandle( h ); + DeleteFileA( filename ); +} + START_TEST(file) { test__hread( ); @@ -1084,4 +1100,5 @@ START_TEST(file) test_file_sharing(); test_offset_in_overlapped_structure(); test_MapFile(); + test_GetFileType(); } diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c index 923d8fe8445..b207170c2e2 100644 --- a/dlls/ntdll/file.c +++ b/dlls/ntdll/file.c @@ -763,129 +763,110 @@ NTSTATUS WINAPI NtSetVolumeInformationFile( * Get information about an open file handle. * * PARAMS - * FileHandle [I] Handle returned from ZwOpenFile() or ZwCreateFile() - * IoStatusBlock [O] Receives information about the operation on return - * FileInformation [O] Destination for file information - * Length [I] Size of FileInformation - * FileInformationClass [I] Type of file information to get + * hFile [I] Handle returned from ZwOpenFile() or ZwCreateFile() + * io [O] Receives information about the operation on return + * ptr [O] Destination for file information + * len [I] Size of FileInformation + * class [I] Type of file information to get * * RETURNS * Success: 0. IoStatusBlock and FileInformation are updated. * Failure: An NTSTATUS error code describing the error. */ -NTSTATUS WINAPI NtQueryInformationFile(HANDLE hFile, PIO_STATUS_BLOCK io_status, - PVOID ptr, LONG len, - FILE_INFORMATION_CLASS class) +NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io, + PVOID ptr, LONG len, FILE_INFORMATION_CLASS class ) { - NTSTATUS status; - LONG used = 0; - BYTE answer[256]; - time_t ct = 0, wt = 0, at = 0; + int fd; - TRACE("(%p,%p,%p,0x%08lx,0x%08x)\n", hFile, io_status, ptr, len, class); + TRACE("(%p,%p,%p,0x%08lx,0x%08x)\n", hFile, io, ptr, len, class); + + io->Information = 0; + if ((io->u.Status = wine_server_handle_to_fd( hFile, 0, &fd, NULL, NULL ))) + return io->u.Status; switch (class) { case FileBasicInformation: { - FILE_BASIC_INFORMATION* fbi = (FILE_BASIC_INFORMATION*)answer; - if (sizeof(answer) < sizeof(*fbi)) goto too_small; + FILE_BASIC_INFORMATION *info = ptr; - SERVER_START_REQ( get_file_info ) + if (len < sizeof(*info)) io->u.Status = STATUS_INFO_LENGTH_MISMATCH; + else { - req->handle = hFile; - if (!(status = wine_server_call( req ))) + struct stat st; + + if (fstat( fd, &st ) == -1) + io->u.Status = FILE_GetNtStatus(); + else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) + io->u.Status = STATUS_INVALID_INFO_CLASS; + else { - /* FIXME: which file types are supported ? - * Serial ports (FILE_TYPE_CHAR) are not, - * and MSDN also says that pipes are not supported. - * FILE_TYPE_REMOTE seems to be supported according to - * MSDN q234741.txt */ - if ((reply->type == FILE_TYPE_DISK) || - (reply->type == FILE_TYPE_REMOTE)) - { - at = reply->access_time; - wt = reply->write_time; - ct = reply->change_time; - fbi->FileAttributes = reply->attr; - used = sizeof(*fbi); - } - else status = STATUS_INVALID_HANDLE; /* FIXME ??? */ + if (S_ISDIR(st.st_mode)) info->FileAttributes = FILE_ATTRIBUTE_DIRECTORY; + else info->FileAttributes = FILE_ATTRIBUTE_ARCHIVE; + if (!(st.st_mode & S_IWUSR)) info->FileAttributes |= FILE_ATTRIBUTE_READONLY; + RtlSecondsSince1970ToTime( st.st_mtime, &info->CreationTime); + RtlSecondsSince1970ToTime( st.st_mtime, &info->LastWriteTime); + RtlSecondsSince1970ToTime( st.st_ctime, &info->ChangeTime); + RtlSecondsSince1970ToTime( st.st_atime, &info->LastAccessTime); } } - SERVER_END_REQ; - if (used) - { - RtlSecondsSince1970ToTime(wt, &fbi->CreationTime); - RtlSecondsSince1970ToTime(wt, &fbi->LastWriteTime); - RtlSecondsSince1970ToTime(ct, &fbi->ChangeTime); - RtlSecondsSince1970ToTime(at, &fbi->LastAccessTime); - } } break; case FileStandardInformation: { - FILE_STANDARD_INFORMATION* fsi = (FILE_STANDARD_INFORMATION*)answer; - if (sizeof(answer) < sizeof(*fsi)) goto too_small; + FILE_STANDARD_INFORMATION *info = ptr; - SERVER_START_REQ( get_file_info ) + if (len < sizeof(*info)) io->u.Status = STATUS_INFO_LENGTH_MISMATCH; + else { - req->handle = hFile; - if (!(status = wine_server_call( req ))) + struct stat st; + + if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus(); + else { - /* FIXME: which file types are supported ? - * Serial ports (FILE_TYPE_CHAR) are not, - * and MSDN also says that pipes are not supported. - * FILE_TYPE_REMOTE seems to be supported according to - * MSDN q234741.txt */ - if ((reply->type == FILE_TYPE_DISK) || - (reply->type == FILE_TYPE_REMOTE)) + if ((info->Directory = S_ISDIR(st.st_mode))) { - fsi->AllocationSize.u.HighPart = reply->alloc_high; - fsi->AllocationSize.u.LowPart = reply->alloc_low; - fsi->EndOfFile.u.HighPart = reply->size_high; - fsi->EndOfFile.u.LowPart = reply->size_low; - fsi->NumberOfLinks = reply->links; - fsi->DeletePending = FALSE; /* FIXME */ - fsi->Directory = (reply->attr & FILE_ATTRIBUTE_DIRECTORY); - used = sizeof(*fsi); + info->AllocationSize.QuadPart = 0; + info->EndOfFile.QuadPart = 0; + info->NumberOfLinks = 1; + info->DeletePending = FALSE; } - else status = STATUS_INVALID_HANDLE; /* FIXME ??? */ + else + { + info->AllocationSize.QuadPart = (ULONGLONG)st.st_blocks * 512; + info->EndOfFile.QuadPart = st.st_size; + info->NumberOfLinks = st.st_nlink; + info->DeletePending = FALSE; /* FIXME */ + } + io->Information = sizeof(*info); } } - SERVER_END_REQ; } break; case FilePositionInformation: { - int fd; - FILE_POSITION_INFORMATION* fpi = (FILE_POSITION_INFORMATION*)answer; + FILE_POSITION_INFORMATION *info = ptr; - if (sizeof(answer) < sizeof(*fpi)) goto too_small; - if (!(status = wine_server_handle_to_fd( hFile, 0, &fd, NULL, NULL ))) + if (len < sizeof(*info)) io->u.Status = STATUS_INFO_LENGTH_MISMATCH; + else { off_t res = lseek( fd, 0, SEEK_CUR ); - if (res == (off_t)-1) status = FILE_GetNtStatus(); + if (res == (off_t)-1) io->u.Status = FILE_GetNtStatus(); else { - fpi->CurrentByteOffset.QuadPart = res; - used = sizeof(*fpi); + info->CurrentByteOffset.QuadPart = res; + io->Information = sizeof(*info); } - wine_server_release_fd( hFile, fd ); } } break; default: FIXME("Unsupported class (%d)\n", class); - return io_status->u.Status = STATUS_NOT_IMPLEMENTED; + io->u.Status = STATUS_NOT_IMPLEMENTED; + break; } - if (used) memcpy(ptr, answer, min(used, len)); - io_status->u.Status = status; - io_status->Information = len; - return status; - too_small: - io_status->Information = 0; - return io_status->u.Status = STATUS_BUFFER_TOO_SMALL; + wine_server_release_fd( hFile, fd ); + return io->u.Status; } /****************************************************************************** diff --git a/files/file.c b/files/file.c index 1e291c7b37f..b57b9a04020 100644 --- a/files/file.c +++ b/files/file.c @@ -497,15 +497,20 @@ static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info ) RtlSecondsSince1970ToTime( st->st_atime, (LARGE_INTEGER *)&info->ftLastAccessTime ); info->dwVolumeSerialNumber = 0; /* FIXME */ - info->nFileSizeHigh = 0; - info->nFileSizeLow = 0; - if (!S_ISDIR(st->st_mode)) { - info->nFileSizeHigh = st->st_size >> 32; - info->nFileSizeLow = st->st_size & 0xffffffff; + if (S_ISDIR(st->st_mode)) + { + info->nFileSizeHigh = 0; + info->nFileSizeLow = 0; + info->nNumberOfLinks = 1; } - info->nNumberOfLinks = st->st_nlink; - info->nFileIndexHigh = 0; - info->nFileIndexLow = st->st_ino; + else + { + info->nFileSizeHigh = st->st_size >> 32; + info->nFileSizeLow = (DWORD)st->st_size; + info->nNumberOfLinks = st->st_nlink; + } + info->nFileIndexHigh = st->st_ino >> 32; + info->nFileIndexLow = (DWORD)st->st_ino; } @@ -599,45 +604,33 @@ BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info, BOOL *is_syml /*********************************************************************** * GetFileInformationByHandle (KERNEL32.@) */ -DWORD WINAPI GetFileInformationByHandle( HANDLE hFile, - BY_HANDLE_FILE_INFORMATION *info ) +BOOL WINAPI GetFileInformationByHandle( HANDLE hFile, BY_HANDLE_FILE_INFORMATION *info ) { - DWORD ret; + NTSTATUS status; + int fd; + BOOL ret = FALSE; + + TRACE("%p,%p\n", hFile, info); + if (!info) return 0; - TRACE("%p\n", hFile); - - SERVER_START_REQ( get_file_info ) + if (!(status = wine_server_handle_to_fd( hFile, 0, &fd, NULL, NULL ))) { - req->handle = hFile; - if ((ret = !wine_server_call_err( req ))) + struct stat st; + + if (fstat( fd, &st ) == -1) + FILE_SetDosError(); + else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) + SetLastError( ERROR_INVALID_FUNCTION ); + else { - /* FIXME: which file types are supported ? - * Serial ports (FILE_TYPE_CHAR) are not, - * and MSDN also says that pipes are not supported. - * FILE_TYPE_REMOTE seems to be supported according to - * MSDN q234741.txt */ - if ((reply->type == FILE_TYPE_DISK) || (reply->type == FILE_TYPE_REMOTE)) - { - RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftCreationTime ); - RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftLastWriteTime ); - RtlSecondsSince1970ToTime( reply->access_time, (LARGE_INTEGER *)&info->ftLastAccessTime ); - info->dwFileAttributes = reply->attr; - info->dwVolumeSerialNumber = reply->serial; - info->nFileSizeHigh = reply->size_high; - info->nFileSizeLow = reply->size_low; - info->nNumberOfLinks = reply->links; - info->nFileIndexHigh = reply->index_high; - info->nFileIndexLow = reply->index_low; - } - else - { - SetLastError(ERROR_NOT_SUPPORTED); - ret = 0; - } + FILE_FillInfo( &st, info ); + ret = TRUE; } + wine_server_release_fd( hFile, fd ); } - SERVER_END_REQ; + else SetLastError( RtlNtStatusToDosError(status) ); + return ret; } @@ -1217,17 +1210,29 @@ BOOL WINAPI SetEndOfFile( HANDLE hFile ) */ DWORD WINAPI GetFileType( HANDLE hFile ) { + NTSTATUS status; + int fd; DWORD ret = FILE_TYPE_UNKNOWN; if (is_console_handle( hFile )) return FILE_TYPE_CHAR; - SERVER_START_REQ( get_file_info ) + if (!(status = wine_server_handle_to_fd( hFile, 0, &fd, NULL, NULL ))) { - req->handle = hFile; - if (!wine_server_call_err( req )) ret = reply->type; + struct stat st; + + if (fstat( fd, &st ) == -1) + FILE_SetDosError(); + else if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode)) + ret = FILE_TYPE_PIPE; + else if (S_ISCHR(st.st_mode)) + ret = FILE_TYPE_CHAR; + else + ret = FILE_TYPE_DISK; + wine_server_release_fd( hFile, fd ); } - SERVER_END_REQ; + else SetLastError( RtlNtStatusToDosError(status) ); + return ret; } diff --git a/include/winbase.h b/include/winbase.h index 539dfa4a457..9c7fcc65c0d 100644 --- a/include/winbase.h +++ b/include/winbase.h @@ -1416,7 +1416,7 @@ DWORD WINAPI GetEnvironmentVariableW(LPCWSTR,LPWSTR,DWORD); BOOL WINAPI GetFileAttributesExA(LPCSTR,GET_FILEEX_INFO_LEVELS,LPVOID); BOOL WINAPI GetFileAttributesExW(LPCWSTR,GET_FILEEX_INFO_LEVELS,LPVOID); #define GetFileAttributesEx WINELIB_NAME_AW(GetFileAttributesEx) -DWORD WINAPI GetFileInformationByHandle(HANDLE,BY_HANDLE_FILE_INFORMATION*); +BOOL WINAPI GetFileInformationByHandle(HANDLE,BY_HANDLE_FILE_INFORMATION*); BOOL WINAPI GetFileSecurityA(LPCSTR,SECURITY_INFORMATION,PSECURITY_DESCRIPTOR,DWORD,LPDWORD); BOOL WINAPI GetFileSecurityW(LPCWSTR,SECURITY_INFORMATION,PSECURITY_DESCRIPTOR,DWORD,LPDWORD); #define GetFileSecurity WINELIB_NAME_AW(GetFileSecurity)