mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
831 lines
17 KiB
831 lines
17 KiB
/*++
|
|
|
|
|
|
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);
|
|
}
|