832 lines
17 KiB
C
832 lines
17 KiB
C
/*++
|
||
|
||
|
||
Copyright (c) 1989 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
fileio.c
|
||
|
||
Abstract:
|
||
|
||
This module implements server performed file io
|
||
|
||
Author:
|
||
|
||
Mark Lucovsky (markl) 27-Nov-1989
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
|
||
#include <sys/stat.h>
|
||
#include <time.h>
|
||
#include <wchar.h>
|
||
#include "psxsrv.h"
|
||
|
||
BOOLEAN
|
||
FileRead (
|
||
IN PPSX_PROCESS p,
|
||
IN OUT PPSX_API_MSG m,
|
||
IN PFILEDESCRIPTOR Fd
|
||
);
|
||
|
||
BOOLEAN
|
||
FileWrite (
|
||
IN PPSX_PROCESS p,
|
||
IN OUT PPSX_API_MSG m,
|
||
IN PFILEDESCRIPTOR Fd
|
||
);
|
||
|
||
BOOLEAN
|
||
FileDup (
|
||
IN PPSX_PROCESS p,
|
||
IN OUT PPSX_API_MSG m,
|
||
IN PFILEDESCRIPTOR Fd,
|
||
IN PFILEDESCRIPTOR FdDup
|
||
);
|
||
|
||
BOOLEAN
|
||
FileLseek (
|
||
IN PPSX_PROCESS p,
|
||
IN OUT PPSX_API_MSG m,
|
||
IN PFILEDESCRIPTOR Fd
|
||
);
|
||
|
||
BOOLEAN
|
||
FileStat (
|
||
IN PIONODE IoNode,
|
||
IN HANDLE FileHandle,
|
||
OUT struct stat *StatBuf,
|
||
OUT NTSTATUS *pStatus
|
||
);
|
||
|
||
void
|
||
FindOwnerModeFile(
|
||
IN HANDLE FileHandle,
|
||
OUT struct stat *StatBuf
|
||
);
|
||
|
||
VOID
|
||
FileLastClose (
|
||
IN PPSX_PROCESS p,
|
||
IN PSYSTEMOPENFILE SystemOpenFile
|
||
)
|
||
{
|
||
NTSTATUS st;
|
||
IO_STATUS_BLOCK Iosb;
|
||
FILE_DISPOSITION_INFORMATION Disp;
|
||
wchar_t buf[PATH_MAX];
|
||
UNICODE_STRING U;
|
||
ANSI_STRING A;
|
||
OBJECT_ATTRIBUTES Obj;
|
||
HANDLE hDir;
|
||
|
||
if (!SystemOpenFile->IoNode->Junked) {
|
||
st = NtClose(SystemOpenFile->NtIoHandle);
|
||
ASSERT(NT_SUCCESS(st));
|
||
return;
|
||
}
|
||
|
||
//
|
||
// This file has been moved to the junkyard, and should now
|
||
// be deleted.
|
||
//
|
||
|
||
Disp.DeleteFile = TRUE;
|
||
st = NtSetInformationFile(SystemOpenFile->NtIoHandle,
|
||
&Iosb, &Disp, sizeof(Disp), FileDispositionInformation);
|
||
if (!NT_SUCCESS(st)) {
|
||
KdPrint(("PSXSS: FileLastClose: SetInfo: 0x%x\n", st));
|
||
}
|
||
st = NtClose(SystemOpenFile->NtIoHandle);
|
||
ASSERT(NT_SUCCESS(st));
|
||
|
||
//
|
||
// Try to delete the directory that held the junked file.
|
||
//
|
||
|
||
swprintf(buf, L"\\DosDevices\\%wc:\\%ws",
|
||
SystemOpenFile->IoNode->DeviceSerialNumber, PSX_JUNK_DIR);
|
||
|
||
U.Buffer = buf;
|
||
U.Length = wcslen(buf) * sizeof(wchar_t);
|
||
U.MaximumLength = sizeof(buf);
|
||
|
||
InitializeObjectAttributes(&Obj, &U, 0, NULL, NULL);
|
||
|
||
st = NtOpenFile(&hDir, SYNCHRONIZE | DELETE,
|
||
&Obj, &Iosb, SHARE_ALL,
|
||
FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE);
|
||
if (!NT_SUCCESS(st)) {
|
||
//null
|
||
} else {
|
||
Disp.DeleteFile = TRUE;
|
||
|
||
st = NtSetInformationFile(hDir, &Iosb,
|
||
&Disp, sizeof(Disp),
|
||
FileDispositionInformation);
|
||
NtClose(hDir);
|
||
}
|
||
}
|
||
|
||
|
||
PSXIO_VECTORS FileVectors = {
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
FileLastClose,
|
||
NULL,
|
||
FileRead,
|
||
FileWrite,
|
||
FileDup,
|
||
FileLseek,
|
||
FileStat
|
||
};
|
||
|
||
|
||
BOOLEAN
|
||
FileWrite (
|
||
IN PPSX_PROCESS p,
|
||
IN OUT PPSX_API_MSG m,
|
||
IN PFILEDESCRIPTOR Fd
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This procedure implements write when the device being written
|
||
is a file.
|
||
|
||
Arguments:
|
||
|
||
p - Supplies the address of the process making the call.
|
||
|
||
m - Supplies the address of the message associated with the request.
|
||
|
||
Fd - supplies the address of the file descriptor being written.
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
|
||
{
|
||
PPSX_WRITE_MSG args;
|
||
NTSTATUS st;
|
||
IO_STATUS_BLOCK Iosb;
|
||
LARGE_INTEGER ByteOffset;
|
||
SIZE_T IoBufferSize;
|
||
FILE_FS_SIZE_INFORMATION SizeInfo;
|
||
ULONG Avail;
|
||
LARGE_INTEGER Time;
|
||
ULONG PosixTime;
|
||
|
||
PVOID IoBuffer = NULL;
|
||
|
||
args = &m->u.Write;
|
||
|
||
// Allocate buffer in server
|
||
|
||
IoBufferSize = args->Nbytes;
|
||
|
||
st = NtAllocateVirtualMemory(NtCurrentProcess(), &IoBuffer, 0,
|
||
&IoBufferSize, MEM_COMMIT, PAGE_READWRITE);
|
||
if (!NT_SUCCESS(st)) {
|
||
m->Error = ENOMEM;
|
||
return TRUE;
|
||
}
|
||
|
||
// Read data from user buffer to server buffer
|
||
|
||
st = NtReadVirtualMemory(p->Process, args->Buf, IoBuffer, args->Nbytes,
|
||
NULL);
|
||
if (!NT_SUCCESS(st)) {
|
||
m->Error = PsxStatusToErrno(st);
|
||
goto out;
|
||
}
|
||
|
||
if (Fd->SystemOpenFileDesc->Flags & PSX_FD_APPEND) {
|
||
ByteOffset = RtlConvertLongToLargeInteger(
|
||
FILE_WRITE_TO_END_OF_FILE);
|
||
} else {
|
||
ByteOffset = RtlConvertLongToLargeInteger(
|
||
FILE_USE_FILE_POINTER_POSITION);
|
||
}
|
||
|
||
st = NtWriteFile(Fd->SystemOpenFileDesc->NtIoHandle, NULL,
|
||
NULL, NULL, &Iosb, IoBuffer, args->Nbytes, &ByteOffset, NULL);
|
||
|
||
if (NT_SUCCESS(st)) {
|
||
|
||
NtQuerySystemTime(&Time);
|
||
if (!RtlTimeToSecondsSince1970(&Time, &PosixTime)) {
|
||
PosixTime = 0;
|
||
}
|
||
|
||
RtlEnterCriticalSection(&Fd->SystemOpenFileDesc->IoNode->IoNodeLock);
|
||
Fd->SystemOpenFileDesc->IoNode->ModifyDataTime = PosixTime;
|
||
Fd->SystemOpenFileDesc->IoNode->ModifyIoNodeTime = PosixTime;
|
||
RtlLeaveCriticalSection(&Fd->SystemOpenFileDesc->IoNode->IoNodeLock);
|
||
m->ReturnValue = (ULONG)Iosb.Information;
|
||
goto out;
|
||
}
|
||
|
||
switch (st) {
|
||
case STATUS_DISK_FULL:
|
||
while (0 != --args->Nbytes) {
|
||
st = NtWriteFile(Fd->SystemOpenFileDesc->NtIoHandle,
|
||
NULL, NULL, NULL, &Iosb, IoBuffer,
|
||
args->Nbytes, &ByteOffset, NULL);
|
||
if (NT_SUCCESS(st)) {
|
||
m->ReturnValue = (ULONG)Iosb.Information;
|
||
goto out;
|
||
}
|
||
}
|
||
m->Error = ENOSPC;
|
||
break;
|
||
default:
|
||
m->Error = EIO;
|
||
break;
|
||
}
|
||
|
||
out:
|
||
st = NtFreeVirtualMemory(NtCurrentProcess(), &IoBuffer, &IoBufferSize,
|
||
MEM_RELEASE);
|
||
if (!NT_SUCCESS(st) ) {
|
||
m->Error = ENOMEM;
|
||
}
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
|
||
|
||
BOOLEAN
|
||
FileRead (
|
||
IN PPSX_PROCESS p,
|
||
IN OUT PPSX_API_MSG m,
|
||
IN PFILEDESCRIPTOR Fd
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This procedure implements read when the device being read
|
||
is a file.
|
||
|
||
Arguments:
|
||
|
||
p - Supplies the address of the process making the call.
|
||
|
||
m - Supplies the address of the message associated with the request.
|
||
|
||
Fd - supplies the address of the file descriptor being read.
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
|
||
{
|
||
PPSX_READ_MSG args;
|
||
PPSX_READDIR_MSG args2;
|
||
NTSTATUS st;
|
||
IO_STATUS_BLOCK Iosb;
|
||
LARGE_INTEGER ByteOffset;
|
||
SIZE_T IoBufferSize;
|
||
LARGE_INTEGER Time;
|
||
ULONG PosixTime;
|
||
|
||
UCHAR Buf[sizeof(FILE_NAMES_INFORMATION) +
|
||
NAME_MAX * sizeof(WCHAR)];
|
||
PFILE_NAMES_INFORMATION pNamesInfo = (PVOID)Buf;
|
||
|
||
PVOID IoBuffer = NULL;
|
||
|
||
args2 = &m->u.ReadDir;
|
||
args = &m->u.Read;
|
||
|
||
//
|
||
// Update the access time on the ionode.
|
||
//
|
||
|
||
NtQuerySystemTime(&Time);
|
||
if (!RtlTimeToSecondsSince1970(&Time, &PosixTime)) {
|
||
PosixTime = 0;
|
||
}
|
||
|
||
RtlEnterCriticalSection(&Fd->SystemOpenFileDesc->IoNode->IoNodeLock);
|
||
Fd->SystemOpenFileDesc->IoNode->AccessDataTime = PosixTime;
|
||
RtlLeaveCriticalSection(&Fd->SystemOpenFileDesc->IoNode->IoNodeLock);
|
||
|
||
|
||
if (S_ISDIR(Fd->SystemOpenFileDesc->IoNode->Mode)) {
|
||
UNICODE_STRING U;
|
||
ANSI_STRING A;
|
||
|
||
st = NtQueryDirectoryFile(
|
||
Fd->SystemOpenFileDesc->NtIoHandle,
|
||
NULL, NULL, NULL, &Iosb,
|
||
&Buf, sizeof(Buf),
|
||
FileNamesInformation, TRUE, NULL,
|
||
args2->RestartScan
|
||
);
|
||
if (STATUS_BUFFER_OVERFLOW == st) {
|
||
m->Error = ENAMETOOLONG;
|
||
return TRUE;
|
||
}
|
||
if (STATUS_NO_MORE_FILES == st) {
|
||
m->ReturnValue = 0;
|
||
return TRUE;
|
||
}
|
||
if (!NT_SUCCESS(st)) {
|
||
m->Error = PsxStatusToErrno(st);
|
||
return TRUE;
|
||
}
|
||
U.Length = U.MaximumLength = (USHORT)pNamesInfo->FileNameLength;
|
||
U.Buffer = pNamesInfo->FileName;
|
||
|
||
st = RtlUnicodeStringToAnsiString(&A, &U, TRUE);
|
||
if (!NT_SUCCESS(st)) {
|
||
m->Error = ENOMEM;
|
||
return TRUE;
|
||
}
|
||
|
||
m->ReturnValue = A.Length;
|
||
st = NtWriteVirtualMemory(p->Process, args2->Buf,
|
||
A.Buffer, A.Length, NULL);
|
||
|
||
RtlFreeAnsiString(&A);
|
||
if (!NT_SUCCESS(st)) {
|
||
m->Error = EIO;
|
||
return TRUE;
|
||
}
|
||
return TRUE;
|
||
}
|
||
|
||
IoBufferSize = args->Nbytes;
|
||
|
||
st = NtAllocateVirtualMemory(NtCurrentProcess(), &IoBuffer, 0,
|
||
&IoBufferSize, MEM_COMMIT, PAGE_READWRITE);
|
||
if (!NT_SUCCESS(st)) {
|
||
m->Error = ENOMEM;
|
||
return TRUE;
|
||
}
|
||
|
||
ByteOffset = RtlConvertLongToLargeInteger(
|
||
FILE_USE_FILE_POINTER_POSITION);
|
||
|
||
st = NtReadFile(Fd->SystemOpenFileDesc->NtIoHandle, NULL, NULL, NULL,
|
||
&Iosb, IoBuffer, args->Nbytes, &ByteOffset, NULL);
|
||
|
||
if (STATUS_END_OF_FILE == st) {
|
||
m->ReturnValue = 0;
|
||
goto out;
|
||
}
|
||
if (!NT_SUCCESS(st)) {
|
||
m->Error = EIO;
|
||
goto out;
|
||
}
|
||
|
||
m->ReturnValue = (ULONG)Iosb.Information;
|
||
|
||
st = NtWriteVirtualMemory(p->Process, args->Buf, IoBuffer,
|
||
args->Nbytes, NULL);
|
||
if (!NT_SUCCESS(st)) {
|
||
m->Error = PsxStatusToErrno(st);
|
||
}
|
||
|
||
out:
|
||
st = NtFreeVirtualMemory(NtCurrentProcess(), &IoBuffer,
|
||
&IoBufferSize, MEM_RELEASE);
|
||
ASSERT(NT_SUCCESS(st));
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
FileDup (
|
||
IN PPSX_PROCESS p,
|
||
IN OUT PPSX_API_MSG m,
|
||
IN PFILEDESCRIPTOR Fd,
|
||
IN PFILEDESCRIPTOR FdDup
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This procedure implements dup and dup2
|
||
|
||
Arguments:
|
||
|
||
p - Supplies the address of the process making the call.
|
||
|
||
m - Supplies the address of the message associated with the request.
|
||
|
||
Fd - supplies the address of the file descriptor being duplicated.
|
||
|
||
FdDup - supplies the address of the duplicate file descriptor.
|
||
|
||
Return Value:
|
||
|
||
???
|
||
--*/
|
||
|
||
{
|
||
PPSX_DUP_MSG args;
|
||
|
||
args = &m->u.Dup;
|
||
|
||
//
|
||
// Copy contents of source file descriptor slot into new descriptor
|
||
// Note that FD_CLOEXEC must be CLEAR on FdDup.
|
||
//
|
||
|
||
*FdDup = *Fd;
|
||
FdDup->Flags &= ~PSX_FD_CLOSE_ON_EXEC;
|
||
|
||
//
|
||
// Increment reference count associated with the SystemOpenFile
|
||
// descriptor for this file.
|
||
//
|
||
|
||
// Grab system open file lock
|
||
|
||
RtlEnterCriticalSection(&SystemOpenFileLock);
|
||
|
||
Fd->SystemOpenFileDesc->HandleCount++;
|
||
|
||
RtlLeaveCriticalSection(&SystemOpenFileLock);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
FileLseek (
|
||
IN PPSX_PROCESS p,
|
||
IN OUT PPSX_API_MSG m,
|
||
IN PFILEDESCRIPTOR Fd
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This procedure implements lseek when the device being seeked on
|
||
is a file.
|
||
|
||
Arguments:
|
||
|
||
p - Supplies the address of the process making the call.
|
||
|
||
m - Supplies the address of the message associated with the request.
|
||
|
||
Fd - supplies the address of the file descriptor being seekd
|
||
|
||
Return Value:
|
||
|
||
???
|
||
|
||
--*/
|
||
|
||
{
|
||
PPSX_LSEEK_MSG args;
|
||
NTSTATUS st;
|
||
IO_STATUS_BLOCK Iosb;
|
||
LARGE_INTEGER Offset, NewByteOffset;
|
||
FILE_POSITION_INFORMATION FilePosition;
|
||
FILE_STANDARD_INFORMATION StandardInfo;
|
||
|
||
args = &m->u.Lseek;
|
||
|
||
Offset = RtlConvertLongToLargeInteger(args->Offset);
|
||
|
||
switch (args->Whence) {
|
||
|
||
case SEEK_SET:
|
||
NewByteOffset = Offset;
|
||
break;
|
||
|
||
case SEEK_CUR:
|
||
st = NtQueryInformationFile(Fd->SystemOpenFileDesc->NtIoHandle,
|
||
&Iosb, &FilePosition, sizeof(FilePosition),
|
||
FilePositionInformation);
|
||
|
||
if (!NT_SUCCESS(st)) {
|
||
m->Error = PsxStatusToErrno(st);
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
NewByteOffset.QuadPart = Offset.QuadPart +
|
||
FilePosition.CurrentByteOffset.QuadPart;
|
||
break;
|
||
|
||
case SEEK_END:
|
||
st = NtQueryInformationFile(Fd->SystemOpenFileDesc->NtIoHandle,
|
||
&Iosb, &StandardInfo, sizeof(StandardInfo),
|
||
FileStandardInformation);
|
||
|
||
if (!NT_SUCCESS(st)) {
|
||
m->Error = PsxStatusToErrno(st);
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
NewByteOffset.QuadPart = Offset.QuadPart +
|
||
StandardInfo.EndOfFile.QuadPart;
|
||
break;
|
||
|
||
default:
|
||
m->Error = EINVAL;
|
||
return TRUE;
|
||
}
|
||
|
||
// Check for overflow. POSIX limited to arithmetic data type for off_t
|
||
|
||
if (NewByteOffset.HighPart != 0 || (off_t)NewByteOffset.LowPart < 0) {
|
||
m->Error = EINVAL;
|
||
return TRUE;
|
||
}
|
||
|
||
FilePosition.CurrentByteOffset = NewByteOffset;
|
||
|
||
args->Offset = NewByteOffset.LowPart;
|
||
|
||
st = NtSetInformationFile(Fd->SystemOpenFileDesc->NtIoHandle, &Iosb,
|
||
&FilePosition, sizeof(FilePosition), FilePositionInformation);
|
||
|
||
if (!NT_SUCCESS(st)) {
|
||
m->Error = EINVAL;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
FileStat (
|
||
IN PIONODE IoNode,
|
||
IN HANDLE FileHandle,
|
||
OUT struct stat *StatBuf,
|
||
OUT NTSTATUS *pStatus
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This procedure implements stat when the device being read
|
||
is a file.
|
||
|
||
Arguments:
|
||
|
||
IoNode - supplies a pointer to the ionode of the file for which stat is
|
||
requested. NULL if no active Ionode entry.
|
||
|
||
FileHandle - supplies the Nt file handle of the file .
|
||
|
||
StatBuf - Supplies the address of the statbuf portion of the message
|
||
associated with the request.
|
||
|
||
Return Value:
|
||
|
||
???
|
||
|
||
--*/
|
||
{
|
||
IO_STATUS_BLOCK Iosb;
|
||
FILE_INTERNAL_INFORMATION SerialNumber;
|
||
FILE_BASIC_INFORMATION BasicInfo;
|
||
FILE_STANDARD_INFORMATION StandardInfo;
|
||
ULONG PosixTime;
|
||
NTSTATUS st;
|
||
|
||
//
|
||
// First get the static information on the file from the ionode if
|
||
// there is one (i.e. if the file currently open.
|
||
// Open() sets the fields in the ionode.
|
||
//
|
||
|
||
if (NULL != IoNode) {
|
||
StatBuf->st_mode = IoNode->Mode;
|
||
StatBuf->st_ino = (ino_t)IoNode->FileSerialNumber;
|
||
StatBuf->st_dev = IoNode->DeviceSerialNumber;
|
||
StatBuf->st_uid = IoNode->OwnerId;
|
||
StatBuf->st_gid = IoNode->GroupId;
|
||
|
||
StatBuf->st_atime = IoNode->AccessDataTime;
|
||
StatBuf->st_ctime = IoNode->ModifyIoNodeTime;
|
||
StatBuf->st_mtime = IoNode->ModifyDataTime;
|
||
} else {
|
||
StatBuf->st_uid = 0;
|
||
StatBuf->st_gid = 0;
|
||
|
||
st = NtQueryInformationFile(FileHandle, &Iosb, &SerialNumber,
|
||
sizeof(SerialNumber), FileInternalInformation);
|
||
if (!NT_SUCCESS(st)) {
|
||
KdPrint(("PSXSS: NtQueryInfoFile failed: 0x%x\n", st));
|
||
*pStatus = st;
|
||
return TRUE;
|
||
}
|
||
|
||
st = NtQueryInformationFile(FileHandle, &Iosb, &BasicInfo,
|
||
sizeof(BasicInfo), FileBasicInformation);
|
||
if (!NT_SUCCESS(st)) {
|
||
//
|
||
// can return STATUS_NO_SUCH_FILE if network
|
||
// file system
|
||
//
|
||
*pStatus = st;
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
StatBuf->st_ino = (ino_t)SerialNumber.IndexNumber.LowPart;
|
||
StatBuf->st_dev = 0;
|
||
StatBuf->st_mode = PsxDetermineFileClass(FileHandle);
|
||
|
||
FindOwnerModeFile(FileHandle, StatBuf);
|
||
|
||
// Convert Nt file times to POSIX ones
|
||
if (!RtlTimeToSecondsSince1970(&BasicInfo.LastAccessTime,
|
||
&PosixTime)) {
|
||
PosixTime = 0L;
|
||
}
|
||
StatBuf->st_atime = PosixTime;
|
||
|
||
if (!RtlTimeToSecondsSince1970(&BasicInfo.LastWriteTime,
|
||
&PosixTime)) {
|
||
PosixTime = 0L;
|
||
}
|
||
StatBuf->st_mtime = PosixTime;
|
||
|
||
if (!RtlTimeToSecondsSince1970(&BasicInfo.ChangeTime,
|
||
&PosixTime)) {
|
||
PosixTime = 0L;
|
||
}
|
||
StatBuf->st_ctime = PosixTime;
|
||
}
|
||
|
||
st = NtQueryInformationFile(FileHandle, &Iosb, &StandardInfo,
|
||
sizeof(StandardInfo), FileStandardInformation);
|
||
if (!NT_SUCCESS(st)) {
|
||
KdPrint(("PSXSS: NtQueryInfoFile(StdInfo): 0x%x\n",
|
||
st));
|
||
*pStatus = st;
|
||
return TRUE;
|
||
}
|
||
|
||
StatBuf->st_size = (off_t)StandardInfo.EndOfFile.LowPart;
|
||
StatBuf->st_nlink = StandardInfo.NumberOfLinks;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
void
|
||
FindOwnerModeFile(
|
||
IN HANDLE FileHandle,
|
||
OUT struct stat *StatBuf
|
||
)
|
||
{
|
||
SECURITY_INFORMATION SecurityInformation;
|
||
ULONG LengthNeeded;
|
||
PSID NtOwner, NtGroup;
|
||
BOOLEAN OwnerDefaulted, GroupDefaulted;
|
||
BOOLEAN AclPresent, AclDefaulted;
|
||
PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
|
||
PACL pAcl;
|
||
NTSTATUS st;
|
||
ACCESS_MASK UserAccess, GroupAccess, OtherAccess;
|
||
|
||
//
|
||
// Get the security descriptor for the file.
|
||
//
|
||
SecurityInformation = OWNER_SECURITY_INFORMATION |
|
||
GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
|
||
|
||
//
|
||
// First try a guess at the necessary descriptor size.
|
||
//
|
||
|
||
LengthNeeded = 2048;
|
||
|
||
SecurityDescriptor = RtlAllocateHeap(PsxHeap, 0, LengthNeeded);
|
||
if (NULL == SecurityDescriptor) {
|
||
return;
|
||
}
|
||
|
||
st = NtQuerySecurityObject(FileHandle, SecurityInformation,
|
||
SecurityDescriptor, LengthNeeded, &LengthNeeded);
|
||
if (STATUS_BUFFER_TOO_SMALL == st) {
|
||
RtlFreeHeap(PsxHeap, 0, (PVOID)SecurityDescriptor);
|
||
SecurityDescriptor = RtlAllocateHeap(PsxHeap, 0, LengthNeeded);
|
||
if (NULL == SecurityDescriptor) {
|
||
return;
|
||
}
|
||
|
||
st = NtQuerySecurityObject(FileHandle, SecurityInformation,
|
||
SecurityDescriptor, LengthNeeded, &LengthNeeded);
|
||
if (!NT_SUCCESS(st)) {
|
||
KdPrint(("PSXSS: FindOwnerModeFile: NtQsObj: 0x%x\n",
|
||
st));
|
||
RtlFreeHeap(PsxHeap, 0, (PVOID)SecurityDescriptor);
|
||
return;
|
||
}
|
||
} else if (!NT_SUCCESS(st)) {
|
||
return;
|
||
}
|
||
|
||
ASSERT(RtlValidSecurityDescriptor(SecurityDescriptor));
|
||
|
||
//
|
||
// Get the owner and group from the security descriptor
|
||
//
|
||
|
||
st = RtlGetOwnerSecurityDescriptor(SecurityDescriptor,
|
||
&NtOwner, &OwnerDefaulted);
|
||
if (!NT_SUCCESS(st)) {
|
||
RtlFreeHeap(PsxHeap, 0, (PVOID)SecurityDescriptor);
|
||
return;
|
||
}
|
||
|
||
st = RtlGetGroupSecurityDescriptor(SecurityDescriptor,
|
||
&NtGroup, &GroupDefaulted);
|
||
ASSERT(NT_SUCCESS(st));
|
||
|
||
if (NULL == NtOwner || NULL == NtGroup) {
|
||
|
||
//
|
||
// Seems like this file doesn't have an owner or a
|
||
// group. Would like to say that it's owned by 'world'
|
||
// or somesuch.
|
||
//
|
||
StatBuf->st_uid = 0;
|
||
StatBuf->st_gid = 0;
|
||
|
||
//
|
||
// Since we don't know who owns the file, we can't
|
||
// figure out what permissions we have on it. Say
|
||
// that all access is granted. We may be lying.
|
||
//
|
||
|
||
StatBuf->st_mode |= _S_PROT;
|
||
|
||
RtlFreeHeap(PsxHeap, 0, (PVOID)SecurityDescriptor);
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Translate Nt uid and gid to Posix recognizable form
|
||
// and set StatBuf->st_uid and StatBuf->st_gid.
|
||
//
|
||
|
||
ASSERT(RtlValidSid(NtOwner));
|
||
ASSERT(RtlValidSid(NtGroup));
|
||
|
||
StatBuf->st_uid = MakePosixId(NtOwner);
|
||
StatBuf->st_gid = MakePosixId(NtGroup);
|
||
|
||
ASSERT(RtlValidSecurityDescriptor(SecurityDescriptor));
|
||
|
||
st = RtlGetDaclSecurityDescriptor(SecurityDescriptor,
|
||
&AclPresent, &pAcl, &AclDefaulted);
|
||
if (!NT_SUCCESS(st)) {
|
||
KdPrint(("PSXSS: RtlGetDaclSD: 0x%x\n", st));
|
||
}
|
||
ASSERT(NT_SUCCESS(st));
|
||
|
||
if (!AclPresent || (AclPresent && NULL == pAcl)) {
|
||
// All access is granted.
|
||
|
||
StatBuf->st_mode |= _S_PROT;
|
||
RtlFreeHeap(PsxHeap, 0, (PVOID)SecurityDescriptor);
|
||
return;
|
||
}
|
||
|
||
//
|
||
// We have a Dacl
|
||
//
|
||
|
||
ASSERT(RtlValidAcl(pAcl));
|
||
|
||
st = RtlInterpretPosixAcl(ACL_REVISION2, NtOwner, NtGroup,
|
||
pAcl, &UserAccess, &GroupAccess, &OtherAccess);
|
||
if (!NT_SUCCESS(st)) {
|
||
//
|
||
// XXX.mjb: The Acl is not a Posix acl. It might be nice to
|
||
// return an error or somesuch.
|
||
//
|
||
RtlFreeHeap(PsxHeap, 0, (PVOID)SecurityDescriptor);
|
||
return;
|
||
}
|
||
|
||
RtlFreeHeap(PsxHeap, 0, (PVOID)SecurityDescriptor);
|
||
StatBuf->st_mode |= AccessMaskToMode(UserAccess, GroupAccess,
|
||
OtherAccess);
|
||
}
|