📄 file.cpp
字号:
//////////////////////////////////////////////////////////////////////////////
// File.cpp
//
// Implementation of class File.
//////////////////////////////////////////////////////////////////////////////
// $Id: File.cpp,v 1.4 1999/03/31 23:51:08 nryan Exp $
// Copyright (C) 1998 by Network Associates, Inc.
// All rights reserved.
#define __w64
#include <vdw.h>
#include "Required.h"
#include "UtilityFunctions.h"
#include "File.h"
#include "KernelModeUtils.h"
#include "NtThreadSecurity.h"
#include "Volume.h"
/////////////////////////////////////
// Class File public member functions
/////////////////////////////////////
// The Class File default constructor.
File::File()
{
mHandle = NULL;
mPath = NULL;
mBlockBuf = NULL;
}
// The destructor for class File will close the file.
File::~File()
{
DualErr derr;
if (Opened())
{
derr = Close();
pgpAssert(derr.IsntError());
}
ClearPath();
}
// IsHostNetworked returns TRUE if the file's host drive is remote.
PGPBoolean
File::IsHostNetworked()
{
pgpAssert(IsPathSet());
return IsNetworkedPath(mPath);
}
// IsPathSet returns TRUE if a path is set, FALSE otherwise.
PGPBoolean
File::IsPathSet()
{
return (IsntNull(mPath));
}
// IsReadOnly returns TRUE if the file has been opened in read-only mode,
// FALSE otherwise.
PGPBoolean
File::IsReadOnly()
{
pgpAssert(Opened());
return mIsReadOnly;
}
// Opened returns TRUE if the file is opened, FALSE if not.
PGPBoolean
File::Opened()
{
return IsntNull(mHandle);
}
// GetLength returns the length of the file in bytes.
DualErr
File::GetLength(PGPUInt64 *pLength)
{
DualErr derr;
FILE_STANDARD_INFORMATION fileInfo;
IO_STATUS_BLOCK ioStatus;
NTSTATUS status;
pgpAssertAddrValid(pLength, PGPUInt32);
pgpAssert(Opened());
status = ZwQueryInformationFile(mHandle, &ioStatus, &fileInfo,
sizeof(fileInfo), FileStandardInformation);
if (!NT_SUCCESS(status))
derr = DualErr(kPGDMinorError_ZwQueryInfoFileFailed, status);
if (derr.IsntError())
{
(* pLength) = fileInfo.EndOfFile.QuadPart;
}
return derr;
}
// SetLength sets the length of the open file to the specified value.
DualErr
File::SetLength(PGPInt64 length)
{
DualErr derr;
FILE_END_OF_FILE_INFORMATION eofInfo;
IO_STATUS_BLOCK ioStatus;
NTSTATUS status;
pgpAssert(Opened());
eofInfo.EndOfFile.QuadPart = length;
status = ZwSetInformationFile(mHandle, &ioStatus, &eofInfo,
sizeof(eofInfo), FileEndOfFileInformation);
if (!NT_SUCCESS(status))
{
derr = DualErr(kPGDMinorError_ZwSetInfoFileFailed, status);
}
return derr;
}
// GetLocalHostDrive returns the drive number of the volume that hosts this
// file, but only if it is a local host.
PGPUInt8
File::GetLocalHostDrive()
{
pgpAssert(!IsUNCPath(mPath));
return DriveLetToNum(mPath[0]);
}
// GetPath returns a constant pointer to the pathname string.
LPCSTR
File::GetPath()
{
return (LPCSTR) mPath;
}
// SetPath sets the filename path variable.
DualErr
File::SetPath(LPCSTR path)
{
DualErr derr;
pgpAssert(!Opened());
ClearPath();
derr = DupeString(path, &mPath);
return derr;
}
// ClearPath clears the filename path variable.
void
File::ClearPath()
{
pgpAssert(!Opened());
if (mPath)
delete[] mPath;
mPath = NULL;
}
// ComparePaths compares the passed pathname with the path of the opened File
// object, returning TRUE if they refer to the same file.
PGPBoolean
File::ComparePaths(LPCSTR path)
{
pgpAssert(Opened());
pgpAssertStrValid(mPath);
pgpAssertStrValid(path);
return (_stricmp(mPath, path) ? FALSE : TRUE);
}
// Open opens the file specified by 'path' with the flags specified by
// 'flags'.
DualErr
File::Open(LPCSTR path, PGPUInt16 flags)
{
DualErr derr;
KUstring uniPath;
NTSTATUS status;
PGPBoolean allocedBlockBuf, denyRead, denyWrite, mustExist;
allocedBlockBuf = denyRead = denyWrite = mustExist = mWeSetPath = FALSE;
mustExist = (flags & kOF_MustExist ? TRUE : FALSE);
mIsReadOnly = (flags & kOF_ReadOnly ? TRUE : FALSE);
denyRead = (flags & kOF_DenyRead ? TRUE : FALSE);
denyWrite = (flags & kOF_DenyWrite ? TRUE : FALSE);
mNoBuffering = (flags & kOF_NoBuffering ? TRUE : FALSE);
// Set the path.
if (IsntNull(path))
{
pgpAssertStrValid(path);
derr = SetPath(path);
mWeSetPath = derr.IsntError();
}
// Convert path to unicode.
if (derr.IsntError())
{
if (IsUNCPath(mPath))
{
derr = AssignToUni(&uniPath, mPath + 2);
if (derr.IsntError())
{
derr = PrependToUni(&uniPath, kNTUNCLinkPathPrefix);
}
}
else
{
derr = AssignToUni(&uniPath, mPath);
if (derr.IsntError())
{
derr = PrependToUni(&uniPath, kNTLinkPathPrefix);
}
}
}
// Get block size of host if needed.
if (derr.IsntError())
{
if (mNoBuffering)
{
if (!IsHostNetworked())
{
Volume vol;
derr = vol.AttachLocalVolume(DriveFromPath(mPath));
if (derr.IsntError())
{
mBlockSize = vol.GetBlockSize();
// Can't be greater than PAGE_SIZE.
if (mBlockSize > PAGE_SIZE)
derr = DualErr(kPGDMinorError_BlockSizeNotSupported);
}
if (vol.AttachedToLocalVolume())
vol.DetachLocalVolume();
}
else
{
mBlockSize = kDefaultBlockSize;
}
}
}
// Create block buffer if needed.
if (derr.IsntError())
{
if (mNoBuffering)
{
derr = GetByteBuffer(PAGE_SIZE, (PGPUInt8 **) &mBlockBuf);
allocedBlockBuf = derr.IsntError();
}
}
if (derr.IsntError())
{
ACCESS_MASK accessMask;
IO_STATUS_BLOCK ioStatus;
OBJECT_ATTRIBUTES objAttribs;
PGPUInt32 createDisp, createOpts, shareAccess;
if (IsHostNetworked())
ImpersonateToken();
// Initialize object attributes
InitializeObjectAttributes(&objAttribs, uniPath,
OBJ_CASE_INSENSITIVE, NULL, NULL);
// Set create options.
createOpts = FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT;
if (mNoBuffering)
createOpts |= FILE_NO_INTERMEDIATE_BUFFERING;
// Set access flags.
accessMask = SYNCHRONIZE | FILE_READ_ACCESS | FILE_WRITE_ACCESS;
if (mIsReadOnly)
accessMask &= ~FILE_WRITE_ACCESS;
// Set share flags.
shareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE;
if (denyRead)
shareAccess &= ~FILE_SHARE_READ;
if (denyWrite)
shareAccess &= ~FILE_SHARE_WRITE;
// Set the create disposition.
if (mustExist)
createDisp = FILE_OPEN;
else
createDisp = FILE_OPEN_IF;
// Open the file.
status = ZwCreateFile(&mHandle, accessMask, &objAttribs, &ioStatus,
0, FILE_ATTRIBUTE_NORMAL, shareAccess, createDisp, createOpts,
NULL, 0);
if (!NT_SUCCESS(status))
derr = DualErr(kPGDMinorError_ZwCreateFileFailed, status);
if (IsHostNetworked())
RevertToSelf();
}
if (derr.IsError())
{
if (allocedBlockBuf)
{
FreeByteBuffer(mBlockBuf);
}
if (mWeSetPath)
{
ClearPath();
mWeSetPath = FALSE;
}
}
return derr;
}
// Close closes a previously opened File object.
DualErr
File::Close()
{
DualErr derr;
NTSTATUS status;
pgpAssert(Opened());
status = ZwClose(mHandle);
if (!NT_SUCCESS(status))
derr = DualErr(kPGDMinorError_ZwCloseFailed, status);
if (derr.IsntError())
{
mHandle = NULL;
if (mNoBuffering)
FreeByteBuffer(mBlockBuf);
if (mWeSetPath)
{
ClearPath();
mWeSetPath = FALSE;
}
}
return derr;
}
// Read reads nBytes from the opened file at position pos (in bytes).
DualErr
File::Read(PGPUInt8 *buf, PGPUInt64 pos, PGPUInt32 nBytes)
{
DualErr derr;
pgpAssert(Opened());
if (IsHostNetworked())
ImpersonateToken();
if (mNoBuffering)
derr = ReadNoBuf(buf, pos, nBytes);
else
derr = ReadBuf(buf, pos, nBytes);
if (IsHostNetworked())
RevertToSelf();
return derr;
}
// Write writes nBytes from the opened file at position pos (in bytes).
DualErr
File::Write(PGPUInt8 *buf, PGPUInt64 pos, PGPUInt32 nBytes)
{
DualErr derr;
pgpAssert(Opened());
pgpAssert(!mIsReadOnly);
if (IsHostNetworked())
ImpersonateToken();
if (derr.IsntError())
{
if (mNoBuffering)
derr = WriteNoBuf(buf, pos, nBytes);
else
derr = WriteBuf(buf, pos, nBytes);
}
if (IsHostNetworked())
RevertToSelf();
return derr;
}
//////////////////////////////////////
// Class File private member functions
//////////////////////////////////////
// ReadBuf reads nBytes from the opened file at position pos (in bytes),
// assuming the file is NOT opened in no-buffering mode.
DualErr
File::ReadBuf(PGPUInt8 *buf, PGPUInt64 pos, PGPUInt32 nBytes)
{
DualErr derr;
IO_STATUS_BLOCK ioStatus;
LARGE_INTEGER bigPos;
NTSTATUS status;
pgpAssertAddrValid(buf, PGPUInt8);
pgpAssert(nBytes > 0);
pgpAssert(Opened());
bigPos.QuadPart = pos;
status = ZwReadFile(mHandle, NULL, NULL, NULL, &ioStatus, buf, nBytes,
&bigPos, NULL);
if (!NT_SUCCESS(status))
derr = DualErr(kPGDMinorError_ZwReadFileFailed, status);
return derr;
}
// WriteBuf writes nBytes from the opened file at position pos (in bytes),
// assuming the file is NOT opened in no-buffering mode.
DualErr
File::WriteBuf(PGPUInt8 *buf, PGPUInt64 pos, PGPUInt32 nBytes)
{
DualErr derr;
IO_STATUS_BLOCK ioStatus;
LARGE_INTEGER bigPos;
NTSTATUS status;
pgpAssertAddrValid(buf, PGPUInt8);
pgpAssert(nBytes > 0);
pgpAssert(Opened());
pgpAssert(!mIsReadOnly);
bigPos.QuadPart = pos;
status = ZwWriteFile(mHandle, NULL, NULL, NULL, &ioStatus, buf, nBytes,
&bigPos, NULL);
if (!NT_SUCCESS(status))
derr = DualErr(kPGDMinorError_ZwWriteFileFailed, status);
return derr;
}
// ReadNoBuf reads nBytes from the opened file at position pos (in bytes),
// assuming the file IS opened in no-buffering mode.
DualErr
File::ReadNoBuf(PGPUInt8 *buf, PGPUInt64 pos, PGPUInt32 nBytes)
{
DualErr derr;
IO_STATUS_BLOCK ioStatus;
LARGE_INTEGER bigPos;
NTSTATUS status;
PGPUInt32 blocksInMiddle, bufPos;
PGPUInt64 blockFile;
pgpAssertAddrValid(buf, PGPUInt8);
pgpAssert(nBytes > 0);
pgpAssert(Opened());
pgpAssert(mNoBuffering);
// The position (pos) and size (nBytes) variables are in bytes, but we
// are reading in blocks. What we have to do is handle the request in at
// most three separate pieces - a head, middle, and end.
bufPos = 0;
if (pos%mBlockSize > 0) // is there a head?
{
PGPUInt32 headOffset, headSize;
// Now read in the head.
//
// blockFile = block in the file containing the head.
// headOffset = byte offset into blockFile where head starts
// headSize = size of the head, in bytes
blockFile = pos/mBlockSize;
headOffset = (PGPUInt32) (pos%mBlockSize);
headSize = min(nBytes, mBlockSize - headOffset);
derr = ReadBuf(mBlockBuf, blockFile*mBlockSize, mBlockSize);
if (derr.IsntError())
{
pgpCopyMemory(mBlockBuf + headOffset, buf, headSize);
bufPos = headSize;
pos += headSize;
nBytes -= headSize;
}
}
// Read in the middle.
if (derr.IsntError())
{
blocksInMiddle = nBytes/mBlockSize;
if (blocksInMiddle > 0) // is there a middle?
{
// Read in all of the middle.
//
// blockFile = block in the PGPdisk where this read begins
blockFile = pos/mBlockSize;
derr = ReadBuf(buf + bufPos, blockFile*mBlockSize,
blocksInMiddle*mBlockSize);
if (derr.IsntError())
{
bufPos += blocksInMiddle * mBlockSize;
nBytes -= blocksInMiddle * mBlockSize;
pos += blocksInMiddle * mBlockSize;
}
}
}
// Read in the tail.
if (derr.IsntError())
{
if (nBytes) // is there a tail?
{
// This read is very simple because we know the tail begins on a
// block boundary.
//
// blockFile = block in the file containing the tail.
blockFile = pos/mBlockSize;
derr = ReadBuf(mBlockBuf, blockFile*mBlockSize, mBlockSize);
if (derr.IsntError())
{
pgpCopyMemory(mBlockBuf, buf + bufPos, nBytes);
}
}
}
return derr;
}
// WriteNoBuf writes nBytes from the opened file at position pos (in bytes).
// assuming the file IS opened in no-buffering mode.
DualErr
File::WriteNoBuf(PGPUInt8 *buf, PGPUInt64 pos, PGPUInt32 nBytes)
{
DualErr derr;
IO_STATUS_BLOCK ioStatus;
LARGE_INTEGER bigPos;
NTSTATUS status;
PGPUInt32 blocksInMiddle, bufPos;
PGPUInt64 blockFile;
pgpAssertAddrValid(buf, PGPUInt8);
pgpAssert(nBytes > 0);
pgpAssert(Opened());
pgpAssert(!mIsReadOnly);
pgpAssert(mNoBuffering);
// The position (pos) and size (nBytes) variables are in bytes, but we
// are writing in blocks. What we have to do is handle the request in at
// most three separate pieces - a head, middle, and end.
bufPos = 0;
if (pos%mBlockSize > 0) // is there a head?
{
PGPUInt32 headOffset, headSize;
// Now write out the head.
//
// blockFile = block in the file file containing the head.
// headOffset = byte offset into blockFile where head starts
// headSize = size of the head, in bytes
blockFile = pos/mBlockSize;
headOffset = (PGPUInt32) (pos%mBlockSize);
headSize = min(nBytes, mBlockSize - headOffset);
derr = ReadBuf(mBlockBuf, blockFile*mBlockSize, mBlockSize);
if (derr.IsntError())
{
pgpCopyMemory(buf, mBlockBuf + headOffset, headSize);
derr = WriteBuf(mBlockBuf, blockFile*mBlockSize, mBlockSize);
bufPos = headSize;
pos += headSize;
nBytes -= headSize;
}
}
// Write out the middle.
if (derr.IsntError()) // is there a middle?
{
blocksInMiddle = nBytes/mBlockSize;
if (blocksInMiddle > 0)
{
// Write out all of the middle.
//
// blockFile = block in the file where this write begins
blockFile = pos/mBlockSize;
derr = WriteBuf(buf + bufPos, blockFile*mBlockSize,
blocksInMiddle*mBlockSize);
if (derr.IsntError())
{
bufPos += blocksInMiddle * mBlockSize;
nBytes -= blocksInMiddle * mBlockSize;
pos += blocksInMiddle * mBlockSize;
}
}
}
// Write out the tail.
if (derr.IsntError())
{
if (nBytes) // is there a tail?
{
// This write is very simple because we know the tail begins on a
// block boundary.
//
// blockFile = the block in the file containing the tail.
derr = ReadBuf(mBlockBuf, blockFile*mBlockSize, mBlockSize);
if (derr.IsntError())
{
pgpCopyMemory(buf, mBlockBuf, nBytes);
derr = WriteBuf(mBlockBuf, blockFile*mBlockSize, mBlockSize);
}
}
}
return derr;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -