ntdll: Move the get/set file information functions to the Unix library.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2020-06-13 15:32:41 +02:00
parent 07248fc500
commit c3e2013b61
7 changed files with 1012 additions and 967 deletions

View File

@ -112,82 +112,9 @@
WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
mode_t FILE_umask = 0;
#define SECSPERDAY 86400
#define SECS_1601_TO_1970 ((369 * 365 + 89) * (ULONGLONG)SECSPERDAY)
#define FILE_WRITE_TO_END_OF_FILE ((LONGLONG)-1)
#define FILE_USE_FILE_POINTER_POSITION ((LONGLONG)-2)
/* fetch the attributes of a file */
static inline ULONG get_file_attributes( const struct stat *st )
{
ULONG attr;
if (S_ISDIR(st->st_mode))
attr = FILE_ATTRIBUTE_DIRECTORY;
else
attr = FILE_ATTRIBUTE_ARCHIVE;
if (!(st->st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
attr |= FILE_ATTRIBUTE_READONLY;
return attr;
}
static BOOL fd_is_mount_point( int fd, const struct stat *st )
{
struct stat parent;
return S_ISDIR( st->st_mode ) && !fstatat( fd, "..", &parent, 0 )
&& (parent.st_dev != st->st_dev || parent.st_ino == st->st_ino);
}
/* get the stat info and file attributes for a file (by file descriptor) */
int fd_get_file_info( int fd, unsigned int options, struct stat *st, ULONG *attr )
{
int ret;
*attr = 0;
ret = fstat( fd, st );
if (ret == -1) return ret;
*attr |= get_file_attributes( st );
/* consider mount points to be reparse points (IO_REPARSE_TAG_MOUNT_POINT) */
if ((options & FILE_OPEN_REPARSE_POINT) && fd_is_mount_point( fd, st ))
*attr |= FILE_ATTRIBUTE_REPARSE_POINT;
return ret;
}
static int get_file_info( const char *path, struct stat *st, ULONG *attr )
{
char *parent_path;
int ret;
*attr = 0;
ret = lstat( path, st );
if (ret == -1) return ret;
if (S_ISLNK( st->st_mode ))
{
ret = stat( path, st );
if (ret == -1) return ret;
/* is a symbolic link and a directory, consider these "reparse points" */
if (S_ISDIR( st->st_mode )) *attr |= FILE_ATTRIBUTE_REPARSE_POINT;
}
else if (S_ISDIR( st->st_mode ) && (parent_path = RtlAllocateHeap( GetProcessHeap(), 0, strlen(path) + 4 )))
{
struct stat parent_st;
/* consider mount points to be reparse points (IO_REPARSE_TAG_MOUNT_POINT) */
strcpy( parent_path, path );
strcat( parent_path, "/.." );
if (!stat( parent_path, &parent_st )
&& (st->st_dev != parent_st.st_dev || st->st_ino == parent_st.st_ino))
*attr |= FILE_ATTRIBUTE_REPARSE_POINT;
RtlFreeHeap( GetProcessHeap(), 0, parent_path );
}
*attr |= get_file_attributes( st );
return ret;
}
/**************************************************************************
* NtOpenFile [NTDLL.@]
@ -1802,244 +1729,6 @@ NTSTATUS WINAPI NtSetVolumeInformationFile(
return 0;
}
#if defined(__ANDROID__) && !defined(HAVE_FUTIMENS)
static int futimens( int fd, const struct timespec spec[2] )
{
return syscall( __NR_utimensat, fd, NULL, spec, 0 );
}
#define HAVE_FUTIMENS
#endif /* __ANDROID__ */
#ifndef UTIME_OMIT
#define UTIME_OMIT ((1 << 30) - 2)
#endif
static BOOL set_file_times_precise( int fd, const LARGE_INTEGER *mtime,
const LARGE_INTEGER *atime, NTSTATUS *status )
{
#ifdef HAVE_FUTIMENS
struct timespec tv[2];
tv[0].tv_sec = tv[1].tv_sec = 0;
tv[0].tv_nsec = tv[1].tv_nsec = UTIME_OMIT;
if (atime->QuadPart)
{
tv[0].tv_sec = atime->QuadPart / 10000000 - SECS_1601_TO_1970;
tv[0].tv_nsec = (atime->QuadPart % 10000000) * 100;
}
if (mtime->QuadPart)
{
tv[1].tv_sec = mtime->QuadPart / 10000000 - SECS_1601_TO_1970;
tv[1].tv_nsec = (mtime->QuadPart % 10000000) * 100;
}
#ifdef __APPLE__
if (!&futimens) return FALSE;
#endif
if (futimens( fd, tv ) == -1) *status = FILE_GetNtStatus();
else *status = STATUS_SUCCESS;
return TRUE;
#else
return FALSE;
#endif
}
static NTSTATUS set_file_times( int fd, const LARGE_INTEGER *mtime, const LARGE_INTEGER *atime )
{
NTSTATUS status = STATUS_SUCCESS;
#if defined(HAVE_FUTIMES) || defined(HAVE_FUTIMESAT)
struct timeval tv[2];
struct stat st;
#endif
if (set_file_times_precise( fd, mtime, atime, &status ))
return status;
#if defined(HAVE_FUTIMES) || defined(HAVE_FUTIMESAT)
if (!atime->QuadPart || !mtime->QuadPart)
{
tv[0].tv_sec = tv[0].tv_usec = 0;
tv[1].tv_sec = tv[1].tv_usec = 0;
if (!fstat( fd, &st ))
{
tv[0].tv_sec = st.st_atime;
tv[1].tv_sec = st.st_mtime;
#ifdef HAVE_STRUCT_STAT_ST_ATIM
tv[0].tv_usec = st.st_atim.tv_nsec / 1000;
#elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC)
tv[0].tv_usec = st.st_atimespec.tv_nsec / 1000;
#endif
#ifdef HAVE_STRUCT_STAT_ST_MTIM
tv[1].tv_usec = st.st_mtim.tv_nsec / 1000;
#elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC)
tv[1].tv_usec = st.st_mtimespec.tv_nsec / 1000;
#endif
}
}
if (atime->QuadPart)
{
tv[0].tv_sec = atime->QuadPart / 10000000 - SECS_1601_TO_1970;
tv[0].tv_usec = (atime->QuadPart % 10000000) / 10;
}
if (mtime->QuadPart)
{
tv[1].tv_sec = mtime->QuadPart / 10000000 - SECS_1601_TO_1970;
tv[1].tv_usec = (mtime->QuadPart % 10000000) / 10;
}
#ifdef HAVE_FUTIMES
if (futimes( fd, tv ) == -1) status = FILE_GetNtStatus();
#elif defined(HAVE_FUTIMESAT)
if (futimesat( fd, NULL, tv ) == -1) status = FILE_GetNtStatus();
#endif
#else /* HAVE_FUTIMES || HAVE_FUTIMESAT */
FIXME( "setting file times not supported\n" );
status = STATUS_NOT_IMPLEMENTED;
#endif
return status;
}
static inline void get_file_times( const struct stat *st, LARGE_INTEGER *mtime, LARGE_INTEGER *ctime,
LARGE_INTEGER *atime, LARGE_INTEGER *creation )
{
RtlSecondsSince1970ToTime( st->st_mtime, mtime );
RtlSecondsSince1970ToTime( st->st_ctime, ctime );
RtlSecondsSince1970ToTime( st->st_atime, atime );
#ifdef HAVE_STRUCT_STAT_ST_MTIM
mtime->QuadPart += st->st_mtim.tv_nsec / 100;
#elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC)
mtime->QuadPart += st->st_mtimespec.tv_nsec / 100;
#endif
#ifdef HAVE_STRUCT_STAT_ST_CTIM
ctime->QuadPart += st->st_ctim.tv_nsec / 100;
#elif defined(HAVE_STRUCT_STAT_ST_CTIMESPEC)
ctime->QuadPart += st->st_ctimespec.tv_nsec / 100;
#endif
#ifdef HAVE_STRUCT_STAT_ST_ATIM
atime->QuadPart += st->st_atim.tv_nsec / 100;
#elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC)
atime->QuadPart += st->st_atimespec.tv_nsec / 100;
#endif
#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME
RtlSecondsSince1970ToTime( st->st_birthtime, creation );
#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIM
creation->QuadPart += st->st_birthtim.tv_nsec / 100;
#elif defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC)
creation->QuadPart += st->st_birthtimespec.tv_nsec / 100;
#endif
#elif defined(HAVE_STRUCT_STAT___ST_BIRTHTIME)
RtlSecondsSince1970ToTime( st->__st_birthtime, creation );
#ifdef HAVE_STRUCT_STAT___ST_BIRTHTIM
creation->QuadPart += st->__st_birthtim.tv_nsec / 100;
#endif
#else
*creation = *mtime;
#endif
}
/* fill in the file information that depends on the stat and attribute info */
NTSTATUS fill_file_info( const struct stat *st, ULONG attr, void *ptr,
FILE_INFORMATION_CLASS class )
{
switch (class)
{
case FileBasicInformation:
{
FILE_BASIC_INFORMATION *info = ptr;
get_file_times( st, &info->LastWriteTime, &info->ChangeTime,
&info->LastAccessTime, &info->CreationTime );
info->FileAttributes = attr;
}
break;
case FileStandardInformation:
{
FILE_STANDARD_INFORMATION *info = ptr;
if ((info->Directory = S_ISDIR(st->st_mode)))
{
info->AllocationSize.QuadPart = 0;
info->EndOfFile.QuadPart = 0;
info->NumberOfLinks = 1;
}
else
{
info->AllocationSize.QuadPart = (ULONGLONG)st->st_blocks * 512;
info->EndOfFile.QuadPart = st->st_size;
info->NumberOfLinks = st->st_nlink;
}
}
break;
case FileInternalInformation:
{
FILE_INTERNAL_INFORMATION *info = ptr;
info->IndexNumber.QuadPart = st->st_ino;
}
break;
case FileEndOfFileInformation:
{
FILE_END_OF_FILE_INFORMATION *info = ptr;
info->EndOfFile.QuadPart = S_ISDIR(st->st_mode) ? 0 : st->st_size;
}
break;
case FileAllInformation:
{
FILE_ALL_INFORMATION *info = ptr;
fill_file_info( st, attr, &info->BasicInformation, FileBasicInformation );
fill_file_info( st, attr, &info->StandardInformation, FileStandardInformation );
fill_file_info( st, attr, &info->InternalInformation, FileInternalInformation );
}
break;
/* all directory structures start with the FileDirectoryInformation layout */
case FileBothDirectoryInformation:
case FileFullDirectoryInformation:
case FileDirectoryInformation:
{
FILE_DIRECTORY_INFORMATION *info = ptr;
get_file_times( st, &info->LastWriteTime, &info->ChangeTime,
&info->LastAccessTime, &info->CreationTime );
if (S_ISDIR(st->st_mode))
{
info->AllocationSize.QuadPart = 0;
info->EndOfFile.QuadPart = 0;
}
else
{
info->AllocationSize.QuadPart = (ULONGLONG)st->st_blocks * 512;
info->EndOfFile.QuadPart = st->st_size;
}
info->FileAttributes = attr;
}
break;
case FileIdFullDirectoryInformation:
{
FILE_ID_FULL_DIRECTORY_INFORMATION *info = ptr;
info->FileId.QuadPart = st->st_ino;
fill_file_info( st, attr, info, FileDirectoryInformation );
}
break;
case FileIdBothDirectoryInformation:
{
FILE_ID_BOTH_DIRECTORY_INFORMATION *info = ptr;
info->FileId.QuadPart = st->st_ino;
fill_file_info( st, attr, info, FileDirectoryInformation );
}
break;
case FileIdGlobalTxDirectoryInformation:
{
FILE_ID_GLOBAL_TX_DIR_INFORMATION *info = ptr;
info->FileId.QuadPart = st->st_ino;
fill_file_info( st, attr, info, FileDirectoryInformation );
}
break;
default:
return STATUS_INVALID_INFO_CLASS;
}
return STATUS_SUCCESS;
}
NTSTATUS server_get_unix_name( HANDLE handle, ANSI_STRING *unix_name )
{
data_size_t size = 1024;
@ -2074,51 +1763,6 @@ NTSTATUS server_get_unix_name( HANDLE handle, ANSI_STRING *unix_name )
return ret;
}
static NTSTATUS fill_name_info( const ANSI_STRING *unix_name, FILE_NAME_INFORMATION *info, LONG *name_len )
{
UNICODE_STRING nt_name;
NTSTATUS status;
if (!(status = wine_unix_to_nt_file_name( unix_name, &nt_name )))
{
const WCHAR *ptr = nt_name.Buffer;
const WCHAR *end = ptr + (nt_name.Length / sizeof(WCHAR));
/* Skip the volume mount point. */
while (ptr != end && *ptr == '\\') ++ptr;
while (ptr != end && *ptr != '\\') ++ptr;
while (ptr != end && *ptr == '\\') ++ptr;
while (ptr != end && *ptr != '\\') ++ptr;
info->FileNameLength = (end - ptr) * sizeof(WCHAR);
if (*name_len < info->FileNameLength) status = STATUS_BUFFER_OVERFLOW;
else *name_len = info->FileNameLength;
memcpy( info->FileName, ptr, *name_len );
RtlFreeUnicodeString( &nt_name );
}
return status;
}
static NTSTATUS server_get_file_info( HANDLE handle, IO_STATUS_BLOCK *io, void *buffer,
ULONG length, FILE_INFORMATION_CLASS info_class )
{
SERVER_START_REQ( get_file_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 );
io->Information = wine_server_reply_size( reply );
}
SERVER_END_REQ;
if (io->u.Status == STATUS_NOT_IMPLEMENTED)
FIXME( "Unsupported info class %x\n", info_class );
return io->u.Status;
}
/* 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 )
@ -2260,288 +1904,7 @@ static struct mountmgr_unix_drive *get_mountmgr_fs_info( HANDLE handle, int fd )
NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io,
PVOID ptr, LONG len, FILE_INFORMATION_CLASS class )
{
static const size_t info_sizes[] =
{
0,
sizeof(FILE_DIRECTORY_INFORMATION), /* FileDirectoryInformation */
sizeof(FILE_FULL_DIRECTORY_INFORMATION), /* FileFullDirectoryInformation */
sizeof(FILE_BOTH_DIRECTORY_INFORMATION), /* FileBothDirectoryInformation */
sizeof(FILE_BASIC_INFORMATION), /* FileBasicInformation */
sizeof(FILE_STANDARD_INFORMATION), /* FileStandardInformation */
sizeof(FILE_INTERNAL_INFORMATION), /* FileInternalInformation */
sizeof(FILE_EA_INFORMATION), /* FileEaInformation */
0, /* FileAccessInformation */
sizeof(FILE_NAME_INFORMATION), /* FileNameInformation */
sizeof(FILE_RENAME_INFORMATION)-sizeof(WCHAR), /* FileRenameInformation */
0, /* FileLinkInformation */
sizeof(FILE_NAMES_INFORMATION)-sizeof(WCHAR), /* FileNamesInformation */
sizeof(FILE_DISPOSITION_INFORMATION), /* FileDispositionInformation */
sizeof(FILE_POSITION_INFORMATION), /* FilePositionInformation */
sizeof(FILE_FULL_EA_INFORMATION), /* FileFullEaInformation */
0, /* FileModeInformation */
sizeof(FILE_ALIGNMENT_INFORMATION), /* FileAlignmentInformation */
sizeof(FILE_ALL_INFORMATION), /* FileAllInformation */
sizeof(FILE_ALLOCATION_INFORMATION), /* FileAllocationInformation */
sizeof(FILE_END_OF_FILE_INFORMATION), /* FileEndOfFileInformation */
0, /* FileAlternateNameInformation */
sizeof(FILE_STREAM_INFORMATION)-sizeof(WCHAR), /* FileStreamInformation */
sizeof(FILE_PIPE_INFORMATION), /* FilePipeInformation */
sizeof(FILE_PIPE_LOCAL_INFORMATION), /* FilePipeLocalInformation */
0, /* FilePipeRemoteInformation */
sizeof(FILE_MAILSLOT_QUERY_INFORMATION), /* FileMailslotQueryInformation */
0, /* FileMailslotSetInformation */
0, /* FileCompressionInformation */
0, /* FileObjectIdInformation */
0, /* FileCompletionInformation */
0, /* FileMoveClusterInformation */
0, /* FileQuotaInformation */
0, /* FileReparsePointInformation */
sizeof(FILE_NETWORK_OPEN_INFORMATION), /* FileNetworkOpenInformation */
sizeof(FILE_ATTRIBUTE_TAG_INFORMATION), /* FileAttributeTagInformation */
0, /* FileTrackingInformation */
0, /* FileIdBothDirectoryInformation */
0, /* FileIdFullDirectoryInformation */
0, /* FileValidDataLengthInformation */
0, /* FileShortNameInformation */
0, /* FileIoCompletionNotificationInformation, */
0, /* FileIoStatusBlockRangeInformation */
0, /* FileIoPriorityHintInformation */
0, /* FileSfioReserveInformation */
0, /* FileSfioVolumeInformation */
0, /* FileHardLinkInformation */
0, /* FileProcessIdsUsingFileInformation */
0, /* FileNormalizedNameInformation */
0, /* FileNetworkPhysicalNameInformation */
0, /* FileIdGlobalTxDirectoryInformation */
0, /* FileIsRemoteDeviceInformation */
0, /* FileAttributeCacheInformation */
0, /* FileNumaNodeInformation */
0, /* FileStandardLinkInformation */
0, /* FileRemoteProtocolInformation */
0, /* FileRenameInformationBypassAccessCheck */
0, /* FileLinkInformationBypassAccessCheck */
0, /* FileVolumeNameInformation */
sizeof(FILE_ID_INFORMATION), /* FileIdInformation */
0, /* FileIdExtdDirectoryInformation */
0, /* FileReplaceCompletionInformation */
0, /* FileHardLinkFullIdInformation */
0, /* FileIdExtdBothDirectoryInformation */
};
struct stat st;
int fd, needs_close = FALSE;
ULONG attr;
unsigned int options;
TRACE("(%p,%p,%p,0x%08x,0x%08x)\n", hFile, io, ptr, len, class);
io->Information = 0;
if (class <= 0 || class >= FileMaximumInformation)
return io->u.Status = STATUS_INVALID_INFO_CLASS;
if (!info_sizes[class])
return server_get_file_info( hFile, io, ptr, len, class );
if (len < info_sizes[class])
return io->u.Status = STATUS_INFO_LENGTH_MISMATCH;
if ((io->u.Status = unix_funcs->server_get_unix_fd( hFile, 0, &fd, &needs_close, NULL, &options )))
{
if (io->u.Status != STATUS_BAD_DEVICE_TYPE) return io->u.Status;
return server_get_file_info( hFile, io, ptr, len, class );
}
switch (class)
{
case FileBasicInformation:
if (fd_get_file_info( fd, options, &st, &attr ) == -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
fill_file_info( &st, attr, ptr, class );
break;
case FileStandardInformation:
{
FILE_STANDARD_INFORMATION *info = ptr;
if (fd_get_file_info( fd, options, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus();
else
{
fill_file_info( &st, attr, info, class );
info->DeletePending = FALSE; /* FIXME */
}
}
break;
case FilePositionInformation:
{
FILE_POSITION_INFORMATION *info = ptr;
off_t res = lseek( fd, 0, SEEK_CUR );
if (res == (off_t)-1) io->u.Status = FILE_GetNtStatus();
else info->CurrentByteOffset.QuadPart = res;
}
break;
case FileInternalInformation:
if (fd_get_file_info( fd, options, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus();
else fill_file_info( &st, attr, ptr, class );
break;
case FileEaInformation:
{
FILE_EA_INFORMATION *info = ptr;
info->EaSize = 0;
}
break;
case FileEndOfFileInformation:
if (fd_get_file_info( fd, options, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus();
else fill_file_info( &st, attr, ptr, class );
break;
case FileAllInformation:
{
FILE_ALL_INFORMATION *info = ptr;
ANSI_STRING unix_name;
if (fd_get_file_info( fd, options, &st, &attr ) == -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 if (!(io->u.Status = server_get_unix_name( hFile, &unix_name )))
{
LONG name_len = len - FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName);
fill_file_info( &st, attr, info, FileAllInformation );
info->StandardInformation.DeletePending = FALSE; /* FIXME */
info->EaInformation.EaSize = 0;
info->AccessInformation.AccessFlags = 0; /* FIXME */
info->PositionInformation.CurrentByteOffset.QuadPart = lseek( fd, 0, SEEK_CUR );
info->ModeInformation.Mode = 0; /* FIXME */
info->AlignmentInformation.AlignmentRequirement = 1; /* FIXME */
io->u.Status = fill_name_info( &unix_name, &info->NameInformation, &name_len );
RtlFreeAnsiString( &unix_name );
io->Information = FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName) + name_len;
}
}
break;
case FileMailslotQueryInformation:
{
FILE_MAILSLOT_QUERY_INFORMATION *info = ptr;
SERVER_START_REQ( set_mailslot_info )
{
req->handle = wine_server_obj_handle( hFile );
req->flags = 0;
io->u.Status = wine_server_call( req );
if( io->u.Status == STATUS_SUCCESS )
{
info->MaximumMessageSize = reply->max_msgsize;
info->MailslotQuota = 0;
info->NextMessageSize = 0;
info->MessagesAvailable = 0;
info->ReadTimeout.QuadPart = reply->read_timeout;
}
}
SERVER_END_REQ;
if (!io->u.Status)
{
char *tmpbuf;
ULONG size = info->MaximumMessageSize ? info->MaximumMessageSize : 0x10000;
if (size > 0x10000) size = 0x10000;
if ((tmpbuf = RtlAllocateHeap( GetProcessHeap(), 0, size )))
{
if (!unix_funcs->server_get_unix_fd( hFile, FILE_READ_DATA, &fd, &needs_close, NULL, NULL ))
{
int res = recv( fd, tmpbuf, size, MSG_PEEK );
info->MessagesAvailable = (res > 0);
info->NextMessageSize = (res >= 0) ? res : MAILSLOT_NO_MESSAGE;
if (needs_close) close( fd );
}
RtlFreeHeap( GetProcessHeap(), 0, tmpbuf );
}
}
}
break;
case FileNameInformation:
{
FILE_NAME_INFORMATION *info = ptr;
ANSI_STRING unix_name;
if (!(io->u.Status = server_get_unix_name( hFile, &unix_name )))
{
LONG name_len = len - FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
io->u.Status = fill_name_info( &unix_name, info, &name_len );
RtlFreeAnsiString( &unix_name );
io->Information = FIELD_OFFSET(FILE_NAME_INFORMATION, FileName) + name_len;
}
}
break;
case FileNetworkOpenInformation:
{
FILE_NETWORK_OPEN_INFORMATION *info = ptr;
ANSI_STRING unix_name;
if (!(io->u.Status = server_get_unix_name( hFile, &unix_name )))
{
ULONG attributes;
struct stat st;
if (get_file_info( unix_name.Buffer, &st, &attributes ) == -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
{
FILE_BASIC_INFORMATION basic;
FILE_STANDARD_INFORMATION std;
fill_file_info( &st, attributes, &basic, FileBasicInformation );
fill_file_info( &st, attributes, &std, FileStandardInformation );
info->CreationTime = basic.CreationTime;
info->LastAccessTime = basic.LastAccessTime;
info->LastWriteTime = basic.LastWriteTime;
info->ChangeTime = basic.ChangeTime;
info->AllocationSize = std.AllocationSize;
info->EndOfFile = std.EndOfFile;
info->FileAttributes = basic.FileAttributes;
}
RtlFreeAnsiString( &unix_name );
}
}
break;
case FileIdInformation:
if (fd_get_file_info( fd, options, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus();
else
{
struct mountmgr_unix_drive *drive;
FILE_ID_INFORMATION *info = ptr;
info->VolumeSerialNumber = 0;
if ((drive = get_mountmgr_fs_info( hFile, fd )))
{
info->VolumeSerialNumber = drive->serial;
RtlFreeHeap( GetProcessHeap(), 0, drive );
}
memset( &info->FileId, 0, sizeof(info->FileId) );
*(ULONGLONG *)&info->FileId = st.st_ino;
}
break;
case FileAttributeTagInformation:
if (fd_get_file_info( fd, options, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus();
else
{
FILE_ATTRIBUTE_TAG_INFORMATION *info = ptr;
info->FileAttributes = attr;
info->ReparseTag = 0; /* FIXME */
if ((options & FILE_OPEN_REPARSE_POINT) && fd_is_mount_point( fd, &st ))
info->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
}
break;
default:
FIXME("Unsupported class (%d)\n", class);
io->u.Status = STATUS_NOT_IMPLEMENTED;
break;
}
if (needs_close) close( fd );
if (io->u.Status == STATUS_SUCCESS && !io->Information) io->Information = info_sizes[class];
return io->u.Status;
return unix_funcs->NtQueryInformationFile( hFile, io, ptr, len, class );
}
/******************************************************************************
@ -2564,317 +1927,7 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io,
NTSTATUS WINAPI NtSetInformationFile(HANDLE handle, PIO_STATUS_BLOCK io,
PVOID ptr, ULONG len, FILE_INFORMATION_CLASS class)
{
int fd, needs_close;
TRACE("(%p,%p,%p,0x%08x,0x%08x)\n", handle, io, ptr, len, class);
io->u.Status = STATUS_SUCCESS;
switch (class)
{
case FileBasicInformation:
if (len >= sizeof(FILE_BASIC_INFORMATION))
{
struct stat st;
const FILE_BASIC_INFORMATION *info = ptr;
LARGE_INTEGER mtime, atime;
if ((io->u.Status = unix_funcs->server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
return io->u.Status;
mtime.QuadPart = info->LastWriteTime.QuadPart == -1 ? 0 : info->LastWriteTime.QuadPart;
atime.QuadPart = info->LastAccessTime.QuadPart == -1 ? 0 : info->LastAccessTime.QuadPart;
if (atime.QuadPart || mtime.QuadPart)
io->u.Status = set_file_times( fd, &mtime, &atime );
if (io->u.Status == STATUS_SUCCESS && info->FileAttributes)
{
if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
else
{
if (info->FileAttributes & FILE_ATTRIBUTE_READONLY)
{
if (S_ISDIR( st.st_mode))
WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
else
st.st_mode &= ~0222; /* clear write permission bits */
}
else
{
/* add write permission only where we already have read permission */
st.st_mode |= (0600 | ((st.st_mode & 044) >> 1)) & (~FILE_umask);
}
if (fchmod( fd, st.st_mode ) == -1) io->u.Status = FILE_GetNtStatus();
}
}
if (needs_close) close( fd );
}
else io->u.Status = STATUS_INVALID_PARAMETER_3;
break;
case FilePositionInformation:
if (len >= sizeof(FILE_POSITION_INFORMATION))
{
const FILE_POSITION_INFORMATION *info = ptr;
if ((io->u.Status = unix_funcs->server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
return io->u.Status;
if (lseek( fd, info->CurrentByteOffset.QuadPart, SEEK_SET ) == (off_t)-1)
io->u.Status = FILE_GetNtStatus();
if (needs_close) close( fd );
}
else io->u.Status = STATUS_INVALID_PARAMETER_3;
break;
case FileEndOfFileInformation:
if (len >= sizeof(FILE_END_OF_FILE_INFORMATION))
{
struct stat st;
const FILE_END_OF_FILE_INFORMATION *info = ptr;
if ((io->u.Status = unix_funcs->server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
return io->u.Status;
/* first try normal truncate */
if (ftruncate( fd, (off_t)info->EndOfFile.QuadPart ) != -1) break;
/* now check for the need to extend the file */
if (fstat( fd, &st ) != -1 && (off_t)info->EndOfFile.QuadPart > st.st_size)
{
static const char zero;
/* extend the file one byte beyond the requested size and then truncate it */
/* this should work around ftruncate implementations that can't extend files */
if (pwrite( fd, &zero, 1, (off_t)info->EndOfFile.QuadPart ) != -1 &&
ftruncate( fd, (off_t)info->EndOfFile.QuadPart ) != -1) break;
}
io->u.Status = FILE_GetNtStatus();
if (needs_close) close( fd );
}
else io->u.Status = STATUS_INVALID_PARAMETER_3;
break;
case FilePipeInformation:
if (len >= sizeof(FILE_PIPE_INFORMATION))
{
FILE_PIPE_INFORMATION *info = ptr;
if ((info->CompletionMode | info->ReadMode) & ~1)
{
io->u.Status = STATUS_INVALID_PARAMETER;
break;
}
SERVER_START_REQ( set_named_pipe_info )
{
req->handle = wine_server_obj_handle( handle );
req->flags = (info->CompletionMode ? NAMED_PIPE_NONBLOCKING_MODE : 0) |
(info->ReadMode ? NAMED_PIPE_MESSAGE_STREAM_READ : 0);
io->u.Status = wine_server_call( req );
}
SERVER_END_REQ;
}
else io->u.Status = STATUS_INVALID_PARAMETER_3;
break;
case FileMailslotSetInformation:
{
FILE_MAILSLOT_SET_INFORMATION *info = ptr;
SERVER_START_REQ( set_mailslot_info )
{
req->handle = wine_server_obj_handle( handle );
req->flags = MAILSLOT_SET_READ_TIMEOUT;
req->read_timeout = info->ReadTimeout.QuadPart;
io->u.Status = wine_server_call( req );
}
SERVER_END_REQ;
}
break;
case FileCompletionInformation:
if (len >= sizeof(FILE_COMPLETION_INFORMATION))
{
FILE_COMPLETION_INFORMATION *info = ptr;
SERVER_START_REQ( set_completion_info )
{
req->handle = wine_server_obj_handle( handle );
req->chandle = wine_server_obj_handle( info->CompletionPort );
req->ckey = info->CompletionKey;
io->u.Status = wine_server_call( req );
}
SERVER_END_REQ;
} else
io->u.Status = STATUS_INVALID_PARAMETER_3;
break;
case FileIoCompletionNotificationInformation:
if (len >= sizeof(FILE_IO_COMPLETION_NOTIFICATION_INFORMATION))
{
FILE_IO_COMPLETION_NOTIFICATION_INFORMATION *info = ptr;
if (info->Flags & FILE_SKIP_SET_USER_EVENT_ON_FAST_IO)
FIXME( "FILE_SKIP_SET_USER_EVENT_ON_FAST_IO not supported\n" );
SERVER_START_REQ( set_fd_completion_mode )
{
req->handle = wine_server_obj_handle( handle );
req->flags = info->Flags;
io->u.Status = wine_server_call( req );
}
SERVER_END_REQ;
} else
io->u.Status = STATUS_INFO_LENGTH_MISMATCH;
break;
case FileIoPriorityHintInformation:
if (len >= sizeof(FILE_IO_PRIORITY_HINT_INFO))
{
FILE_IO_PRIORITY_HINT_INFO *info = ptr;
if (info->PriorityHint < MaximumIoPriorityHintType)
TRACE( "ignoring FileIoPriorityHintInformation %u\n", info->PriorityHint );
else
io->u.Status = STATUS_INVALID_PARAMETER;
}
else io->u.Status = STATUS_INFO_LENGTH_MISMATCH;
break;
case FileAllInformation:
io->u.Status = STATUS_INVALID_INFO_CLASS;
break;
case FileValidDataLengthInformation:
if (len >= sizeof(FILE_VALID_DATA_LENGTH_INFORMATION))
{
struct stat st;
const FILE_VALID_DATA_LENGTH_INFORMATION *info = ptr;
if ((io->u.Status = unix_funcs->server_get_unix_fd( handle, FILE_WRITE_DATA, &fd, &needs_close, NULL, NULL )))
return io->u.Status;
if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
else if (info->ValidDataLength.QuadPart <= 0 || (off_t)info->ValidDataLength.QuadPart > st.st_size)
io->u.Status = STATUS_INVALID_PARAMETER;
else
{
#ifdef HAVE_FALLOCATE
if (fallocate( fd, 0, 0, (off_t)info->ValidDataLength.QuadPart ) == -1)
{
NTSTATUS status = FILE_GetNtStatus();
if (status == STATUS_NOT_SUPPORTED) WARN( "fallocate not supported on this filesystem\n" );
else io->u.Status = status;
}
#else
FIXME( "setting valid data length not supported\n" );
#endif
}
if (needs_close) close( fd );
}
else io->u.Status = STATUS_INVALID_PARAMETER_3;
break;
case FileDispositionInformation:
if (len >= sizeof(FILE_DISPOSITION_INFORMATION))
{
FILE_DISPOSITION_INFORMATION *info = ptr;
SERVER_START_REQ( set_fd_disp_info )
{
req->handle = wine_server_obj_handle( handle );
req->unlink = info->DoDeleteFile;
io->u.Status = wine_server_call( req );
}
SERVER_END_REQ;
} else
io->u.Status = STATUS_INVALID_PARAMETER_3;
break;
case FileRenameInformation:
if (len >= sizeof(FILE_RENAME_INFORMATION))
{
FILE_RENAME_INFORMATION *info = ptr;
UNICODE_STRING name_str;
OBJECT_ATTRIBUTES attr;
ANSI_STRING unix_name;
name_str.Buffer = info->FileName;
name_str.Length = info->FileNameLength;
name_str.MaximumLength = info->FileNameLength + sizeof(WCHAR);
attr.Length = sizeof(attr);
attr.ObjectName = &name_str;
attr.RootDirectory = info->RootDirectory;
attr.Attributes = OBJ_CASE_INSENSITIVE;
io->u.Status = unix_funcs->nt_to_unix_file_name_attr( &attr, &unix_name, FILE_OPEN_IF );
if (io->u.Status != STATUS_SUCCESS && io->u.Status != STATUS_NO_SUCH_FILE)
break;
SERVER_START_REQ( set_fd_name_info )
{
req->handle = wine_server_obj_handle( handle );
req->rootdir = wine_server_obj_handle( attr.RootDirectory );
req->link = FALSE;
req->replace = info->ReplaceIfExists;
wine_server_add_data( req, unix_name.Buffer, unix_name.Length );
io->u.Status = wine_server_call( req );
}
SERVER_END_REQ;
RtlFreeAnsiString( &unix_name );
}
else io->u.Status = STATUS_INVALID_PARAMETER_3;
break;
case FileLinkInformation:
if (len >= sizeof(FILE_LINK_INFORMATION))
{
FILE_LINK_INFORMATION *info = ptr;
UNICODE_STRING name_str;
OBJECT_ATTRIBUTES attr;
ANSI_STRING unix_name;
name_str.Buffer = info->FileName;
name_str.Length = info->FileNameLength;
name_str.MaximumLength = info->FileNameLength + sizeof(WCHAR);
attr.Length = sizeof(attr);
attr.ObjectName = &name_str;
attr.RootDirectory = info->RootDirectory;
attr.Attributes = OBJ_CASE_INSENSITIVE;
io->u.Status = unix_funcs->nt_to_unix_file_name_attr( &attr, &unix_name, FILE_OPEN_IF );
if (io->u.Status != STATUS_SUCCESS && io->u.Status != STATUS_NO_SUCH_FILE)
break;
SERVER_START_REQ( set_fd_name_info )
{
req->handle = wine_server_obj_handle( handle );
req->rootdir = wine_server_obj_handle( attr.RootDirectory );
req->link = TRUE;
req->replace = info->ReplaceIfExists;
wine_server_add_data( req, unix_name.Buffer, unix_name.Length );
io->u.Status = wine_server_call( req );
}
SERVER_END_REQ;
RtlFreeAnsiString( &unix_name );
}
else io->u.Status = STATUS_INVALID_PARAMETER_3;
break;
default:
FIXME("Unsupported class (%d)\n", class);
io->u.Status = STATUS_NOT_IMPLEMENTED;
break;
}
io->Information = 0;
return io->u.Status;
return unix_funcs->NtSetInformationFile( handle, io, ptr, len, class );
}

View File

@ -4384,10 +4384,6 @@ void __wine_process_init(void)
init_user_process_params( info_size );
params = peb->ProcessParameters;
/* retrieve current umask */
FILE_umask = umask(0777);
umask( FILE_umask );
load_global_options();
version_init();

View File

@ -203,7 +203,6 @@ static inline int get_unix_exit_code( NTSTATUS status )
return status;
}
extern mode_t FILE_umask DECLSPEC_HIDDEN;
extern SYSTEM_CPU_INFORMATION cpu_info DECLSPEC_HIDDEN;
#define HASH_STRING_ALGORITHM_DEFAULT 0

File diff suppressed because it is too large Load Diff

View File

@ -864,6 +864,7 @@ static struct unix_funcs unix_funcs =
NtQueryDirectoryFile,
NtQueryEvent,
NtQueryFullAttributesFile,
NtQueryInformationFile,
NtQueryInformationJobObject,
NtQueryIoCompletion,
NtQueryMutant,
@ -886,6 +887,7 @@ static struct unix_funcs unix_funcs =
NtResumeThread,
NtSetContextThread,
NtSetEvent,
NtSetInformationFile,
NtSetInformationJobObject,
NtSetIoCompletion,
NtSetLdtEntries,
@ -955,8 +957,6 @@ static struct unix_funcs unix_funcs =
server_handle_to_fd,
server_release_fd,
server_init_process_done,
file_id_to_unix_file_name,
nt_to_unix_file_name_attr,
nt_to_unix_file_name,
unmount_device,
set_show_dot_files,

View File

@ -120,9 +120,6 @@ extern NTSTATUS CDECL exec_process( const UNICODE_STRING *cmdline, const pe_imag
extern NTSTATUS CDECL fork_and_exec( const char *unix_name, const char *unix_dir,
const RTL_USER_PROCESS_PARAMETERS *params ) DECLSPEC_HIDDEN;
extern NTSTATUS CDECL file_id_to_unix_file_name( const OBJECT_ATTRIBUTES *attr, ANSI_STRING *unix_name ) DECLSPEC_HIDDEN;
extern NTSTATUS CDECL nt_to_unix_file_name_attr( const OBJECT_ATTRIBUTES *attr, ANSI_STRING *unix_name_ret,
UINT disposition ) DECLSPEC_HIDDEN;
extern NTSTATUS CDECL nt_to_unix_file_name( const UNICODE_STRING *nameW, ANSI_STRING *unix_name_ret,
UINT disposition, BOOLEAN check_case ) DECLSPEC_HIDDEN;
extern NTSTATUS CDECL unmount_device( HANDLE handle ) DECLSPEC_HIDDEN;

View File

@ -28,7 +28,7 @@ struct ldt_copy;
struct msghdr;
/* increment this when you change the function table */
#define NTDLL_UNIXLIB_VERSION 45
#define NTDLL_UNIXLIB_VERSION 46
struct unix_funcs
{
@ -129,6 +129,8 @@ struct unix_funcs
void *info, ULONG len, ULONG *ret_len );
NTSTATUS (WINAPI *NtQueryFullAttributesFile)( const OBJECT_ATTRIBUTES *attr,
FILE_NETWORK_OPEN_INFORMATION *info );
NTSTATUS (WINAPI *NtQueryInformationFile)( HANDLE hFile, IO_STATUS_BLOCK *io,
void *ptr, LONG len, FILE_INFORMATION_CLASS class );
NTSTATUS (WINAPI *NtQueryInformationJobObject)( HANDLE handle, JOBOBJECTINFOCLASS class,
void *info, ULONG len, ULONG *ret_len );
NTSTATUS (WINAPI *NtQueryIoCompletion)( HANDLE handle, IO_COMPLETION_INFORMATION_CLASS class,
@ -165,6 +167,8 @@ struct unix_funcs
NTSTATUS (WINAPI *NtResumeThread)( HANDLE handle, ULONG *count );
NTSTATUS (WINAPI *NtSetContextThread)( HANDLE handle, const CONTEXT *context );
NTSTATUS (WINAPI *NtSetEvent)( HANDLE handle, LONG *prev_state );
NTSTATUS (WINAPI *NtSetInformationFile)( HANDLE handle, IO_STATUS_BLOCK *io,
void *ptr, ULONG len, FILE_INFORMATION_CLASS class );
NTSTATUS (WINAPI *NtSetInformationJobObject)( HANDLE handle, JOBOBJECTINFOCLASS class,
void *info, ULONG len );
NTSTATUS (WINAPI *NtSetIoCompletion)( HANDLE handle, ULONG_PTR key, ULONG_PTR value,
@ -273,10 +277,6 @@ struct unix_funcs
void (CDECL *server_init_process_done)( void *relay );
/* file functions */
NTSTATUS (CDECL *file_id_to_unix_file_name)( const OBJECT_ATTRIBUTES *attr,
ANSI_STRING *unix_name );
NTSTATUS (CDECL *nt_to_unix_file_name_attr)( const OBJECT_ATTRIBUTES *attr,
ANSI_STRING *unix_name_ret, UINT disposition );
NTSTATUS (CDECL *nt_to_unix_file_name)( const UNICODE_STRING *nameW, ANSI_STRING *unix_name_ret,
UINT disposition, BOOLEAN check_case );
NTSTATUS (CDECL *unmount_device)( HANDLE handle );